From dbe3e156d7cae963e188820d5ce617987149138f Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 17 Apr 2023 22:24:28 -0300 Subject: [PATCH 01/73] 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/73] 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/73] 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/73] 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/73] 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/73] 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/73] 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 10/73] 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 11/73] 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 571f407ef3eadfaa695f896c1cdc812a3f49ae47 Mon Sep 17 00:00:00 2001 From: Ibis Prevedello Date: Mon, 17 Apr 2023 15:59:15 -0300 Subject: [PATCH 12/73] refac: refactor tools and add QuerySQLDataBaseTool --- src/backend/langflow/config.yaml | 4 + .../langflow/interface/importing/utils.py | 4 +- src/backend/langflow/interface/tools/base.py | 110 +++++++++--------- .../langflow/interface/tools/constants.py | 3 + src/backend/langflow/interface/tools/util.py | 24 +--- 5 files changed, 66 insertions(+), 79 deletions(-) diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index 7f00167b4..3508f5196 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -40,6 +40,10 @@ tools: - Tool - PythonFunction - JsonSpec + - News API + - TMDB API + - Podcast API + - QuerySQLDataBaseTool wrappers: - RequestsWrapper diff --git a/src/backend/langflow/interface/importing/utils.py b/src/backend/langflow/interface/importing/utils.py index a3480928e..c426eaf85 100644 --- a/src/backend/langflow/interface/importing/utils.py +++ b/src/backend/langflow/interface/importing/utils.py @@ -10,7 +10,7 @@ from langchain.chat_models.base import BaseChatModel from langchain.llms.base import BaseLLM from langchain.tools import BaseTool -from langflow.interface.tools.util import get_tool_by_name +from langflow.interface.tools.base import tool_creator def import_module(module_path: str) -> Any: @@ -107,7 +107,7 @@ def import_llm(llm: str) -> BaseLLM: def import_tool(tool: str) -> BaseTool: """Import tool from tool name""" - return get_tool_by_name(tool) + return tool_creator.type_to_loader_dict[tool]["fcn"] def import_chain(chain: str) -> Type[Chain]: diff --git a/src/backend/langflow/interface/tools/base.py b/src/backend/langflow/interface/tools/base.py index 6a3439bf0..a5745f1d3 100644 --- a/src/backend/langflow/interface/tools/base.py +++ b/src/backend/langflow/interface/tools/base.py @@ -1,7 +1,7 @@ +import inspect from typing import Dict, List, Optional from langchain.agents.load_tools import ( - _BASE_TOOLS, _EXTRA_LLM_TOOLS, _EXTRA_OPTIONAL_TOOLS, _LLM_TOOLS, @@ -10,17 +10,16 @@ from langchain.agents.load_tools import ( from langflow.custom import customs from langflow.interface.base import LangChainTypeCreator from langflow.interface.tools.constants import ( + ALL_TOOLS_NAMES, CUSTOM_TOOLS, FILE_TOOLS, + OTHER_TOOLS, ) -from langflow.interface.tools.util import ( - get_tool_by_name, - get_tool_params, - get_tools_dict, -) +from langflow.interface.tools.util import get_tool_params from langflow.settings import settings from langflow.template.base import Template, TemplateField from langflow.utils import util +from langflow.utils.util import build_template_from_class TOOL_INPUTS = { "str": TemplateField( @@ -66,64 +65,79 @@ class ToolCreator(LangChainTypeCreator): @property def type_to_loader_dict(self) -> Dict: if self.tools_dict is None: - self.tools_dict = get_tools_dict() + all_tools = {} + for tool, tool_fcn in ALL_TOOLS_NAMES.items(): + tool_params = get_tool_params(tool_fcn) + tool_name = tool_params.get("name", tool) + + if tool_name in settings.tools or settings.dev: + if tool_name == "JsonSpec": + tool_params["path"] = tool_params.pop("dict_") # type: ignore + all_tools[tool_name] = { + "type": tool, + "params": tool_params, + "fcn": tool_fcn, + } + + self.tools_dict = all_tools + return self.tools_dict def get_signature(self, name: str) -> Optional[Dict]: """Get the signature of a tool.""" base_classes = ["Tool"] - all_tools = {} - for tool in self.type_to_loader_dict.keys(): - tool_fcn = get_tool_by_name(tool) - if tool_params := get_tool_params(tool_fcn): - tool_name = tool_params.get("name") or str(tool) - all_tools[tool_name] = { - "type": tool, - "params": tool_params, - "fcn": tool_fcn, - } + fields = [] + params = [] + tool_params = {} # Raise error if name is not in tools - if name not in all_tools.keys(): + if name not in self.type_to_loader_dict.keys(): raise ValueError("Tool not found") - tool_type: str = all_tools[name]["type"] # type: ignore + tool_type: str = self.type_to_loader_dict[name]["type"] # type: ignore - if all_tools[tool_type]["fcn"] in _BASE_TOOLS.values(): - params = [] - elif all_tools[tool_type]["fcn"] in _LLM_TOOLS.values(): + # if tool_type in _BASE_TOOLS.keys(): + # params = [] + if tool_type in _LLM_TOOLS.keys(): params = ["llm"] - elif all_tools[tool_type]["fcn"] in [ - val[0] for val in _EXTRA_LLM_TOOLS.values() - ]: - n_dict = {val[0]: val[1] for val in _EXTRA_LLM_TOOLS.values()} - extra_keys = n_dict[all_tools[tool_type]["fcn"]] + elif tool_type in _EXTRA_LLM_TOOLS.keys(): + extra_keys = _EXTRA_LLM_TOOLS[tool_type][1] params = ["llm"] + extra_keys - elif all_tools[tool_type]["fcn"] in [ - val[0] for val in _EXTRA_OPTIONAL_TOOLS.values() - ]: - n_dict = {val[0]: val[1] for val in _EXTRA_OPTIONAL_TOOLS.values()} # type: ignore - extra_keys = n_dict[all_tools[tool_type]["fcn"]] + elif tool_type in _EXTRA_OPTIONAL_TOOLS.keys(): + extra_keys = _EXTRA_OPTIONAL_TOOLS[tool_type][1] params = extra_keys # elif tool_type == "Tool": # params = ["name", "description", "func"] elif tool_type in CUSTOM_TOOLS: # Get custom tool params - params = all_tools[name]["params"] # type: ignore + params = self.type_to_loader_dict[name]["params"] # type: ignore base_classes = ["function"] if node := customs.get_custom_nodes("tools").get(tool_type): return node elif tool_type in FILE_TOOLS: - params = all_tools[name]["params"] # type: ignore - if tool_type == "JsonSpec": - params["path"] = params.pop("dict_") # type: ignore + params = self.type_to_loader_dict[name]["params"] # type: ignore base_classes += [name] - else: - params = [] + elif tool_type in OTHER_TOOLS: + tool_dict = build_template_from_class(tool_type, OTHER_TOOLS) + fields = tool_dict["template"] + + # Pop unnecessary fields and add name + fields.pop("_type") + fields.pop("return_direct") + fields.pop("verbose") + + tool_params = { + "name": fields.pop("name")["value"], + "description": fields.pop("description")["value"], + } + + fields = [ + TemplateField(name=name, **field) for name, field in fields.items() + ] + base_classes += tool_dict["base_classes"] # Copy the field and add the name - fields = [] for param in params: field = TOOL_INPUTS.get(param, TOOL_INPUTS["str"]).copy() field.name = param @@ -134,7 +148,7 @@ class ToolCreator(LangChainTypeCreator): template = Template(fields=fields, type_name=tool_type) - tool_params = all_tools[name]["params"] + tool_params = {**tool_params, **self.type_to_loader_dict[name]["params"]} return { "template": util.format_dict(template.to_dict()), **tool_params, @@ -144,21 +158,7 @@ class ToolCreator(LangChainTypeCreator): def to_list(self) -> List[str]: """List all load tools""" - tools = [] - - for tool, fcn in get_tools_dict().items(): - tool_params = get_tool_params(fcn) - - if tool_params and not tool_params.get("name"): - tool_params["name"] = tool - - if tool_params and ( - tool_params.get("name") in settings.tools - or (tool_params.get("name") and settings.dev) - ): - tools.append(tool_params["name"]) - - return tools + return list(self.type_to_loader_dict.keys()) tool_creator = ToolCreator() diff --git a/src/backend/langflow/interface/tools/constants.py b/src/backend/langflow/interface/tools/constants.py index 2ec20cef9..101fefa8b 100644 --- a/src/backend/langflow/interface/tools/constants.py +++ b/src/backend/langflow/interface/tools/constants.py @@ -6,11 +6,13 @@ from langchain.agents.load_tools import ( _LLM_TOOLS, ) from langchain.tools.json.tool import JsonSpec +from langchain.tools.sql_database.tool import QuerySQLDataBaseTool from langflow.interface.tools.custom import PythonFunction FILE_TOOLS = {"JsonSpec": JsonSpec} CUSTOM_TOOLS = {"Tool": Tool, "PythonFunction": PythonFunction} +OTHER_TOOLS = {"QuerySQLDataBaseTool": QuerySQLDataBaseTool} ALL_TOOLS_NAMES = { **_BASE_TOOLS, **_LLM_TOOLS, # type: ignore @@ -18,4 +20,5 @@ ALL_TOOLS_NAMES = { **{k: v[0] for k, v in _EXTRA_OPTIONAL_TOOLS.items()}, **CUSTOM_TOOLS, **FILE_TOOLS, # type: ignore + **OTHER_TOOLS, } diff --git a/src/backend/langflow/interface/tools/util.py b/src/backend/langflow/interface/tools/util.py index 8f8673b6b..41fb4bdb7 100644 --- a/src/backend/langflow/interface/tools/util.py +++ b/src/backend/langflow/interface/tools/util.py @@ -4,28 +4,6 @@ from typing import Dict, Union from langchain.agents.tools import Tool -from langflow.interface.tools.constants import ALL_TOOLS_NAMES - - -def get_tools_dict(): - """Get the tools dictionary.""" - - all_tools = {} - - for tool, fcn in ALL_TOOLS_NAMES.items(): - if tool_params := get_tool_params(fcn): - tool_name = tool_params.get("name") or str(tool) - all_tools[tool_name] = fcn - - return all_tools - - -def get_tool_by_name(name: str): - """Get a tool from the tools dictionary.""" - tools = get_tools_dict() - if name not in tools: - raise ValueError(f"{name} not found.") - return tools[name] def get_func_tool_params(func, **kwargs) -> Union[Dict, None]: @@ -113,6 +91,8 @@ def get_tool_params(tool, **kwargs) -> Dict: elif inspect.isclass(tool): # Get the parameters necessary to # instantiate the class + return get_class_tool_params(tool, **kwargs) or {} + else: raise ValueError("Tool must be a function or class.") From 843ae8efc50253bdea3fd9385a5e646a905ab34e Mon Sep 17 00:00:00 2001 From: Ibis Prevedello Date: Mon, 17 Apr 2023 23:15:39 -0300 Subject: [PATCH 13/73] feat: add extra tools and utilities --- src/backend/langflow/config.yaml | 28 +++++++++++++ .../langflow/interface/custom_lists.py | 6 +++ src/backend/langflow/interface/listing.py | 2 + src/backend/langflow/interface/tools/base.py | 14 ++++--- .../langflow/interface/tools/constants.py | 42 +++++++++++++++++-- src/backend/langflow/interface/tools/util.py | 1 - src/backend/langflow/interface/types.py | 2 + .../langflow/interface/utilities/__init__.py | 0 .../langflow/interface/utilities/base.py | 36 ++++++++++++++++ src/backend/langflow/settings.py | 2 + src/frontend/src/utils.ts | 6 ++- 11 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 src/backend/langflow/interface/utilities/__init__.py create mode 100644 src/backend/langflow/interface/utilities/base.py diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index 3508f5196..605df68ad 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -44,6 +44,23 @@ tools: - TMDB API - Podcast API - QuerySQLDataBaseTool + - InfoSQLDatabaseTool + - ListSQLDatabaseTool + # - QueryCheckerTool + - BingSearchRun + - GoogleSearchRun + - GoogleSearchResults + - JsonListKeysTool + - JsonGetValueTool + - PythonREPLTool + - PythonAstREPLTool + - RequestsGetTool + - RequestsPostTool + - RequestsPatchTool + - RequestsPutTool + - RequestsDeleteTool + - WikipediaQueryRun + - WolframAlphaQueryRun wrappers: - RequestsWrapper @@ -95,4 +112,15 @@ documentloaders: textsplitters: - CharacterTextSplitter +utilities: + - BingSearchAPIWrapper + - GoogleSearchAPIWrapper + - GoogleSerperAPIWrapper + - SearxResults + - SearxSearchWrapper + - SerpAPIWrapper + - WikipediaAPIWrapper + - WolframAlphaAPIWrapper + # - ZapierNLAWrapper + dev: false diff --git a/src/backend/langflow/interface/custom_lists.py b/src/backend/langflow/interface/custom_lists.py index 2ffc18b14..fb97e8dae 100644 --- a/src/backend/langflow/interface/custom_lists.py +++ b/src/backend/langflow/interface/custom_lists.py @@ -9,6 +9,7 @@ from langchain import ( memory, requests, text_splitter, + utilities, vectorstores, ) from langchain.agents import agent_toolkits @@ -76,3 +77,8 @@ documentloaders_type_to_cls_dict: dict[str, Any] = { textsplitter_type_to_cls_dict: dict[str, Any] = dict( inspect.getmembers(text_splitter, inspect.isclass) ) + +## Utilities +utility_type_to_cls_dict: dict[str, Any] = dict( + inspect.getmembers(utilities, inspect.isclass) +) diff --git a/src/backend/langflow/interface/listing.py b/src/backend/langflow/interface/listing.py index cf45fd9c5..3d73105c2 100644 --- a/src/backend/langflow/interface/listing.py +++ b/src/backend/langflow/interface/listing.py @@ -8,6 +8,7 @@ from langflow.interface.prompts.base import prompt_creator from langflow.interface.text_splitters.base import textsplitter_creator from langflow.interface.toolkits.base import toolkits_creator from langflow.interface.tools.base import tool_creator +from langflow.interface.utilities.base import utility_creator from langflow.interface.vector_store.base import vectorstore_creator from langflow.interface.wrappers.base import wrapper_creator @@ -26,6 +27,7 @@ def get_type_dict(): "vectorStore": vectorstore_creator.to_list(), "embeddings": embedding_creator.to_list(), "textSplitters": textsplitter_creator.to_list(), + "utilities": utility_creator.to_list(), } diff --git a/src/backend/langflow/interface/tools/base.py b/src/backend/langflow/interface/tools/base.py index a5745f1d3..f236831d8 100644 --- a/src/backend/langflow/interface/tools/base.py +++ b/src/backend/langflow/interface/tools/base.py @@ -119,21 +119,23 @@ class ToolCreator(LangChainTypeCreator): params = self.type_to_loader_dict[name]["params"] # type: ignore base_classes += [name] elif tool_type in OTHER_TOOLS: + print(tool_type) tool_dict = build_template_from_class(tool_type, OTHER_TOOLS) fields = tool_dict["template"] # Pop unnecessary fields and add name - fields.pop("_type") - fields.pop("return_direct") - fields.pop("verbose") + fields.pop("_type") # type: ignore + fields.pop("return_direct") # type: ignore + fields.pop("verbose") # type: ignore tool_params = { - "name": fields.pop("name")["value"], - "description": fields.pop("description")["value"], + "name": fields.pop("name")["value"], # type: ignore + "description": fields.pop("description")["value"], # type: ignore } fields = [ - TemplateField(name=name, **field) for name, field in fields.items() + TemplateField(name=name, field_type=field["type"], **field) + for name, field in fields.items() # type: ignore ] base_classes += tool_dict["base_classes"] diff --git a/src/backend/langflow/interface/tools/constants.py b/src/backend/langflow/interface/tools/constants.py index 101fefa8b..34890a684 100644 --- a/src/backend/langflow/interface/tools/constants.py +++ b/src/backend/langflow/interface/tools/constants.py @@ -5,14 +5,50 @@ from langchain.agents.load_tools import ( _EXTRA_OPTIONAL_TOOLS, _LLM_TOOLS, ) -from langchain.tools.json.tool import JsonSpec -from langchain.tools.sql_database.tool import QuerySQLDataBaseTool +from langchain.tools.bing_search.tool import BingSearchRun +from langchain.tools.google_search.tool import GoogleSearchResults, GoogleSearchRun +from langchain.tools.json.tool import JsonGetValueTool, JsonListKeysTool, JsonSpec +from langchain.tools.python.tool import PythonAstREPLTool, PythonREPLTool +from langchain.tools.requests.tool import ( + RequestsDeleteTool, + RequestsGetTool, + RequestsPatchTool, + RequestsPostTool, + RequestsPutTool, +) +from langchain.tools.sql_database.tool import ( + InfoSQLDatabaseTool, + ListSQLDatabaseTool, + QueryCheckerTool, + QuerySQLDataBaseTool, +) +from langchain.tools.wikipedia.tool import WikipediaQueryRun +from langchain.tools.wolfram_alpha.tool import WolframAlphaQueryRun from langflow.interface.tools.custom import PythonFunction FILE_TOOLS = {"JsonSpec": JsonSpec} CUSTOM_TOOLS = {"Tool": Tool, "PythonFunction": PythonFunction} -OTHER_TOOLS = {"QuerySQLDataBaseTool": QuerySQLDataBaseTool} +OTHER_TOOLS = { + "QuerySQLDataBaseTool": QuerySQLDataBaseTool, + "InfoSQLDatabaseTool": InfoSQLDatabaseTool, + "ListSQLDatabaseTool": ListSQLDatabaseTool, + "QueryCheckerTool": QueryCheckerTool, + "BingSearchRun": BingSearchRun, + "GoogleSearchRun": GoogleSearchRun, + "GoogleSearchResults": GoogleSearchResults, + "JsonListKeysTool": JsonListKeysTool, + "JsonGetValueTool": JsonGetValueTool, + "PythonREPLTool": PythonREPLTool, + "PythonAstREPLTool": PythonAstREPLTool, + "RequestsGetTool": RequestsGetTool, + "RequestsPostTool": RequestsPostTool, + "RequestsPatchTool": RequestsPatchTool, + "RequestsPutTool": RequestsPutTool, + "RequestsDeleteTool": RequestsDeleteTool, + "WikipediaQueryRun": WikipediaQueryRun, + "WolframAlphaQueryRun": WolframAlphaQueryRun, +} ALL_TOOLS_NAMES = { **_BASE_TOOLS, **_LLM_TOOLS, # type: ignore diff --git a/src/backend/langflow/interface/tools/util.py b/src/backend/langflow/interface/tools/util.py index 41fb4bdb7..f1d66696a 100644 --- a/src/backend/langflow/interface/tools/util.py +++ b/src/backend/langflow/interface/tools/util.py @@ -5,7 +5,6 @@ from typing import Dict, Union from langchain.agents.tools import Tool - def get_func_tool_params(func, **kwargs) -> Union[Dict, None]: tree = ast.parse(inspect.getsource(func)) diff --git a/src/backend/langflow/interface/types.py b/src/backend/langflow/interface/types.py index fd5d9ec3e..085537756 100644 --- a/src/backend/langflow/interface/types.py +++ b/src/backend/langflow/interface/types.py @@ -8,6 +8,7 @@ from langflow.interface.prompts.base import prompt_creator from langflow.interface.text_splitters.base import textsplitter_creator from langflow.interface.toolkits.base import toolkits_creator from langflow.interface.tools.base import tool_creator +from langflow.interface.utilities.base import utility_creator from langflow.interface.vector_store.base import vectorstore_creator from langflow.interface.wrappers.base import wrapper_creator @@ -42,6 +43,7 @@ def build_langchain_types_dict(): # sourcery skip: dict-assign-update-to-union vectorstore_creator, documentloader_creator, textsplitter_creator, + utility_creator, ] all_types = {} diff --git a/src/backend/langflow/interface/utilities/__init__.py b/src/backend/langflow/interface/utilities/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/langflow/interface/utilities/base.py b/src/backend/langflow/interface/utilities/base.py new file mode 100644 index 000000000..a56e8bce8 --- /dev/null +++ b/src/backend/langflow/interface/utilities/base.py @@ -0,0 +1,36 @@ +from typing import Dict, List, Optional + +from langflow.interface.base import LangChainTypeCreator +from langflow.interface.custom_lists import utility_type_to_cls_dict +from langflow.settings import settings +from langflow.utils.logger import logger +from langflow.utils.util import build_template_from_class + + +class UtilityCreator(LangChainTypeCreator): + type_name: str = "utilities" + + @property + def type_to_loader_dict(self) -> Dict: + return utility_type_to_cls_dict + + def get_signature(self, name: str) -> Optional[Dict]: + """Get the signature of a utility.""" + try: + return build_template_from_class(name, utility_type_to_cls_dict) + except ValueError as exc: + raise ValueError(f"Utility {name} not found") from exc + + except AttributeError as exc: + logger.error(f"Utility {name} not loaded: {exc}") + return None + + def to_list(self) -> List[str]: + return [ + utility.__name__ + for utility in self.type_to_loader_dict.values() + if utility.__name__ in settings.utilities or settings.dev + ] + + +utility_creator = UtilityCreator() diff --git a/src/backend/langflow/settings.py b/src/backend/langflow/settings.py index c5377c85a..48aa5939d 100644 --- a/src/backend/langflow/settings.py +++ b/src/backend/langflow/settings.py @@ -18,6 +18,7 @@ class Settings(BaseSettings): wrappers: List[str] = [] toolkits: List[str] = [] textsplitters: List[str] = [] + utilities: List[str] = [] dev: bool = False class Config: @@ -42,6 +43,7 @@ class Settings(BaseSettings): self.wrappers = new_settings.wrappers or [] self.toolkits = new_settings.toolkits or [] self.textsplitters = new_settings.textsplitters or [] + self.utilities = new_settings.utilities or [] self.dev = new_settings.dev or False diff --git a/src/frontend/src/utils.ts b/src/frontend/src/utils.ts index 5ab47f31e..405d56297 100644 --- a/src/frontend/src/utils.ts +++ b/src/frontend/src/utils.ts @@ -13,7 +13,8 @@ import { QuestionMarkCircleIcon, FingerPrintIcon, ScissorsIcon, - CircleStackIcon + CircleStackIcon, + Squares2X2Icon } from "@heroicons/react/24/outline"; import { Connection, Edge, Node, ReactFlowInstance } from "reactflow"; import { FlowType } from "./types/flow"; @@ -85,6 +86,7 @@ export const nodeColors: {[char: string]: string} = { textsplitters: "#B47CB5", toolkits:"#DB2C2C", wrappers:"#E6277A", + utilities:"#31A3CC", unknown:"#9CA3AF" }; @@ -103,6 +105,7 @@ export const nodeNames:{[char: string]: string} = { toolkits:"Toolkits", wrappers:"Wrappers", textsplitters: "Text Splitters", + utilities:"Utilities", unknown:"Unknown" }; @@ -121,6 +124,7 @@ export const nodeIcons:{[char: string]: React.ForwardRefExoticComponent Date: Wed, 19 Apr 2023 10:31:13 -0300 Subject: [PATCH 14/73] feat: add SQLDatabaseChain Close #173 --- src/backend/langflow/config.yaml | 2 ++ src/backend/langflow/custom/customs.py | 3 +++ src/backend/langflow/graph/base.py | 6 ++++- src/backend/langflow/graph/nodes.py | 4 ++++ .../langflow/interface/custom_lists.py | 2 ++ .../langflow/interface/importing/utils.py | 9 +++++++- src/backend/langflow/interface/loading.py | 3 +++ src/backend/langflow/interface/tools/base.py | 1 - .../langflow/interface/utilities/base.py | 3 +++ src/backend/langflow/template/nodes.py | 23 +++++++++++++++++++ 10 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index 605df68ad..9236d5996 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -6,6 +6,7 @@ chains: - SeriesCharacterChain - MidJourneyPromptChain - TimeTravelGuideChain + - SQLDatabaseChain agents: - ZeroShotAgent @@ -122,5 +123,6 @@ utilities: - WikipediaAPIWrapper - WolframAlphaAPIWrapper # - ZapierNLAWrapper + - SQLDatabase dev: false diff --git a/src/backend/langflow/custom/customs.py b/src/backend/langflow/custom/customs.py index e77b81ec6..d45221be7 100644 --- a/src/backend/langflow/custom/customs.py +++ b/src/backend/langflow/custom/customs.py @@ -12,6 +12,9 @@ CUSTOM_NODES = { "VectorStoreRouterAgent": nodes.VectorStoreRouterAgentNode(), "SQLAgent": nodes.SQLAgentNode(), }, + "utilities": { + "SQLDatabase": nodes.SQLDatabaseNode(), + }, } diff --git a/src/backend/langflow/graph/base.py b/src/backend/langflow/graph/base.py index ff586c6da..6d998eed6 100644 --- a/src/backend/langflow/graph/base.py +++ b/src/backend/langflow/graph/base.py @@ -202,7 +202,11 @@ class Node: "VectorStoreRouterAgent", "VectorStoreAgent", "VectorStoreInfo", - ] or self.node_type in ["VectorStoreInfo", "VectorStoreRouterToolkit"]: + ] or self.node_type in [ + "VectorStoreInfo", + "VectorStoreRouterToolkit", + "SQLDatabase", + ]: return self._built_object return deepcopy(self._built_object) diff --git a/src/backend/langflow/graph/nodes.py b/src/backend/langflow/graph/nodes.py index 7296a0c0d..018174334 100644 --- a/src/backend/langflow/graph/nodes.py +++ b/src/backend/langflow/graph/nodes.py @@ -101,6 +101,10 @@ class ChainNode(Node): self.params[key] = value.build(tools=tools, force=force) self._build() + + #! Cannot deepcopy SQLDatabaseChain + if self.node_type in ["SQLDatabaseChain"]: + return self._built_object return deepcopy(self._built_object) diff --git a/src/backend/langflow/interface/custom_lists.py b/src/backend/langflow/interface/custom_lists.py index fb97e8dae..f07b03f04 100644 --- a/src/backend/langflow/interface/custom_lists.py +++ b/src/backend/langflow/interface/custom_lists.py @@ -14,6 +14,7 @@ from langchain import ( ) from langchain.agents import agent_toolkits from langchain.chat_models import ChatOpenAI +from langchain.sql_database import SQLDatabase from langflow.interface.importing.utils import import_class @@ -82,3 +83,4 @@ textsplitter_type_to_cls_dict: dict[str, Any] = dict( utility_type_to_cls_dict: dict[str, Any] = dict( inspect.getmembers(utilities, inspect.isclass) ) +utility_type_to_cls_dict["SQLDatabase"] = SQLDatabase diff --git a/src/backend/langflow/interface/importing/utils.py b/src/backend/langflow/interface/importing/utils.py index c426eaf85..e303da0eb 100644 --- a/src/backend/langflow/interface/importing/utils.py +++ b/src/backend/langflow/interface/importing/utils.py @@ -44,6 +44,7 @@ def import_by_type(_type: str, name: str) -> Any: "vectorstores": import_vectorstore, "documentloaders": import_documentloader, "textsplitters": import_textsplitter, + "utilities": import_utility, } if _type == "llms": key = "chat" if "chat" in name.lower() else "llm" @@ -131,10 +132,16 @@ def import_vectorstore(vectorstore: str) -> Any: def import_documentloader(documentloader: str) -> Any: """Import documentloader from documentloader name""" - return import_class(f"langchain.document_loaders.{documentloader}") def import_textsplitter(textsplitter: str) -> Any: """Import textsplitter from textsplitter name""" return import_class(f"langchain.text_splitter.{textsplitter}") + + +def import_utility(utility: str) -> Any: + """Import utility from utility name""" + if utility == "SQLDatabase": + return import_class(f"langchain.sql_database.{utility}") + return import_class(f"langchain.utilities.{utility}") diff --git a/src/backend/langflow/interface/loading.py b/src/backend/langflow/interface/loading.py index 11db47ee6..0fa1c5f2e 100644 --- a/src/backend/langflow/interface/loading.py +++ b/src/backend/langflow/interface/loading.py @@ -75,6 +75,9 @@ def instantiate_class(node_type: str, base_type: str, params: Dict) -> Any: documents = params.pop("documents") text_splitter = class_object(**params) return text_splitter.split_documents(documents) + elif base_type == "utilities": + if node_type == "SQLDatabase": + return class_object.from_uri(params.pop("uri")) return class_object(**params) diff --git a/src/backend/langflow/interface/tools/base.py b/src/backend/langflow/interface/tools/base.py index f236831d8..5fd0c72f0 100644 --- a/src/backend/langflow/interface/tools/base.py +++ b/src/backend/langflow/interface/tools/base.py @@ -1,4 +1,3 @@ -import inspect from typing import Dict, List, Optional from langchain.agents.load_tools import ( diff --git a/src/backend/langflow/interface/utilities/base.py b/src/backend/langflow/interface/utilities/base.py index a56e8bce8..e60e344ad 100644 --- a/src/backend/langflow/interface/utilities/base.py +++ b/src/backend/langflow/interface/utilities/base.py @@ -1,5 +1,6 @@ from typing import Dict, List, Optional +from langflow.custom.customs import get_custom_nodes from langflow.interface.base import LangChainTypeCreator from langflow.interface.custom_lists import utility_type_to_cls_dict from langflow.settings import settings @@ -17,6 +18,8 @@ class UtilityCreator(LangChainTypeCreator): def get_signature(self, name: str) -> Optional[Dict]: """Get the signature of a utility.""" try: + if name in get_custom_nodes(self.type_name).keys(): + return get_custom_nodes(self.type_name)[name] return build_template_from_class(name, utility_type_to_cls_dict) except ValueError as exc: raise ValueError(f"Utility {name} not found") from exc diff --git a/src/backend/langflow/template/nodes.py b/src/backend/langflow/template/nodes.py index 6ac026e59..f2e8bd94f 100644 --- a/src/backend/langflow/template/nodes.py +++ b/src/backend/langflow/template/nodes.py @@ -256,6 +256,29 @@ class CSVAgentNode(FrontendNode): return super().to_dict() +class SQLDatabaseNode(FrontendNode): + name: str = "SQLDatabase" + template: Template = Template( + type_name="sql_database", + fields=[ + TemplateField( + field_type="str", + required=True, + is_list=False, + show=True, + multiline=False, + value="", + name="uri", + ), + ], + ) + description: str = """SQLAlchemy wrapper around a database.""" + base_classes: list[str] = ["SQLDatabase"] + + def to_dict(self): + return super().to_dict() + + class VectorStoreAgentNode(FrontendNode): name: str = "VectorStoreAgent" template: Template = Template( From 68f69e878ec4d3aa82487145d44a3601c2396123 Mon Sep 17 00:00:00 2001 From: Petru Molla Date: Mon, 17 Apr 2023 17:38:44 +0300 Subject: [PATCH 15/73] Using an exported Flow JSON file with load_flow_from_json("path/to/flow.json") returns "UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 9465: character maps to ". Specifying the encodint type in the function helps to fix that error. --- src/backend/langflow/interface/loading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/interface/loading.py b/src/backend/langflow/interface/loading.py index 0fa1c5f2e..0d4465e7e 100644 --- a/src/backend/langflow/interface/loading.py +++ b/src/backend/langflow/interface/loading.py @@ -87,7 +87,7 @@ def load_flow_from_json(path: str): from langflow.graph import Graph """Load flow from json file""" - with open(path, "r") as f: + with open(path, "r", encoding='utf-8') as f: flow_graph = json.load(f) data_graph = flow_graph["data"] nodes = data_graph["nodes"] From ded527a64a257896a0ab0222b2105f5f179ba99b Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 20 Apr 2023 15:18:59 -0300 Subject: [PATCH 16/73] Update loading.py --- src/backend/langflow/interface/loading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/interface/loading.py b/src/backend/langflow/interface/loading.py index 0d4465e7e..333c0307c 100644 --- a/src/backend/langflow/interface/loading.py +++ b/src/backend/langflow/interface/loading.py @@ -87,7 +87,7 @@ def load_flow_from_json(path: str): from langflow.graph import Graph """Load flow from json file""" - with open(path, "r", encoding='utf-8') as f: + with open(path, "r", encoding=utf-8") as f: flow_graph = json.load(f) data_graph = flow_graph["data"] nodes = data_graph["nodes"] From 801ff57dc085f9e4ae74702760ccf321c05572e1 Mon Sep 17 00:00:00 2001 From: Petru Molla <112887899+bigKeter@users.noreply.github.com> Date: Thu, 20 Apr 2023 21:56:10 +0300 Subject: [PATCH 17/73] Update loading.py --- src/backend/langflow/interface/loading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/interface/loading.py b/src/backend/langflow/interface/loading.py index 333c0307c..3e3accef0 100644 --- a/src/backend/langflow/interface/loading.py +++ b/src/backend/langflow/interface/loading.py @@ -87,7 +87,7 @@ def load_flow_from_json(path: str): from langflow.graph import Graph """Load flow from json file""" - with open(path, "r", encoding=utf-8") as f: + with open(path, "r", encoding="utf-8") as f: flow_graph = json.load(f) data_graph = flow_graph["data"] nodes = data_graph["nodes"] From 2465318f77e679d7ed3c9ddf38c4e380126df7f5 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Tue, 18 Apr 2023 03:07:05 +0000 Subject: [PATCH 18/73] Add steps to provision GCP VM serving langflow --- GCP-SETUP.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 GCP-SETUP.md diff --git a/GCP-SETUP.md b/GCP-SETUP.md new file mode 100644 index 000000000..ba6d61404 --- /dev/null +++ b/GCP-SETUP.md @@ -0,0 +1,90 @@ +# Running Langflow from a new GCP project +## Run the following in your GCP cloudshell: + +```bash + +VM_NAME="langflow-dev" +IMAGE_FAMILY="debian-11" +IMAGE_PROJECT="debian-cloud" +BOOT_DISK_SIZE="100GB" +ZONE="us-central1-a" +REGION="us-central1" +VPC_NAME="default" +SUBNET_NAME="default" +NAT_GATEWAY_NAME="nat-gateway" +CLOUD_ROUTER_NAME="nat-client" + +gcloud config set compute/region $REGION + +# Verify the VPC and subnet exist +vpc_exists=$(gcloud compute networks list --filter="name=$VPC_NAME" --format="value(name)") +subnet_exists=$(gcloud compute networks subnets list --filter="name=$SUBNET_NAME AND region=$REGION" --format="value(name)") + +if [[ -z "$vpc_exists" || -z "$subnet_exists" ]]; then + echo "Error: VPC '$VPC_NAME' and/or subnet '$SUBNET_NAME' do not exist in region '$REGION'." + exit 1 +fi + +# Create the Cloud Router and NAT Gateway +gcloud compute routers create $CLOUD_ROUTER_NAME \ + --network $VPC_NAME \ + --region $REGION + +gcloud compute routers nats create $NAT_GATEWAY_NAME \ + --router $CLOUD_ROUTER_NAME \ + --auto-allocate-nat-external-ips \ + --nat-all-subnet-ip-ranges \ + --enable-logging \ + --region $REGION + +# Define the startup script as a multiline Bash here-doc +STARTUP_SCRIPT=$(cat <<'EOF' +#!/bin/bash + +apt update +apt upgrade +apt install python3-pip +pip install langflow +apt-get install nginx +touch /etc/nginx/sites-available/langflow-app +echo "server { + listen 0.0.0.0:7860; + + location / { + proxy_pass http://127.0.0.1:7860; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +}" >> /etc/nginx/sites-available/langflow-app +ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl restart nginx +langflow +EOF +) + +# Create a temporary file to store the startup script +tempfile=$(mktemp) +echo "$STARTUP_SCRIPT" > $tempfile + +gcloud compute instances create $VM_NAME \ + --image-family $IMAGE_FAMILY \ + --image-project $IMAGE_PROJECT \ + --boot-disk-size $BOOT_DISK_SIZE \ + --metadata-from-file startup-script=$tempfile \ + --zone $ZONE \ + --network $VPC_NAME \ + --subnet $SUBNET_NAME + +# Remove the temporary file after the VM is created +rm $tempfile + +``` + +## Connecting to your new Langflow VM +1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page +2. Click on the external IP for your VM +3. Add port 8080 (assuming your VM external IP is 192.168.0.1): +http://192.168.0.1:8080 +4. You will be greeted by the Langflow Dev environment \ No newline at end of file From 7011721c3cbe49d7bf2b6a09aca1845f154a473b Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Tue, 18 Apr 2023 03:14:45 +0000 Subject: [PATCH 19/73] Adjust firewall to allow port 8080 --- GCP-SETUP.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/GCP-SETUP.md b/GCP-SETUP.md index ba6d61404..53646d4b0 100644 --- a/GCP-SETUP.md +++ b/GCP-SETUP.md @@ -25,6 +25,13 @@ if [[ -z "$vpc_exists" || -z "$subnet_exists" ]]; then exit 1 fi +gcloud compute firewall-rules create allow-tcp-8080 \ + --network $VPC_NAME \ + --allow tcp:8080 \ + --source-ranges 0.0.0.0/0 \ + --direction INGRESS + + # Create the Cloud Router and NAT Gateway gcloud compute routers create $CLOUD_ROUTER_NAME \ --network $VPC_NAME \ From d6b179b7ce2dfd42b408f2e9a736624c9f2bfcfe Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Tue, 18 Apr 2023 03:42:01 +0000 Subject: [PATCH 20/73] Add comments to clarify code --- GCP-SETUP.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/GCP-SETUP.md b/GCP-SETUP.md index 53646d4b0..1f4eb6b4e 100644 --- a/GCP-SETUP.md +++ b/GCP-SETUP.md @@ -1,8 +1,11 @@ # Running Langflow from a new GCP project +This guide will help you set up a Langflow Dev VM in a Google Cloud Platform project using Google Cloud Shell. + + ## Run the following in your GCP cloudshell: ```bash - +# Set the VM, image, and networking configuration VM_NAME="langflow-dev" IMAGE_FAMILY="debian-11" IMAGE_PROJECT="debian-cloud" @@ -14,17 +17,20 @@ SUBNET_NAME="default" NAT_GATEWAY_NAME="nat-gateway" CLOUD_ROUTER_NAME="nat-client" +# Set the GCP project's compute region gcloud config set compute/region $REGION # Verify the VPC and subnet exist vpc_exists=$(gcloud compute networks list --filter="name=$VPC_NAME" --format="value(name)") subnet_exists=$(gcloud compute networks subnets list --filter="name=$SUBNET_NAME AND region=$REGION" --format="value(name)") +# Exit with an error message if the VPC or subnet does not exist if [[ -z "$vpc_exists" || -z "$subnet_exists" ]]; then echo "Error: VPC '$VPC_NAME' and/or subnet '$SUBNET_NAME' do not exist in region '$REGION'." exit 1 fi +# Create a firewall rule to allow TCP port 8080 for all instances in the VPC gcloud compute firewall-rules create allow-tcp-8080 \ --network $VPC_NAME \ --allow tcp:8080 \ @@ -48,11 +54,16 @@ gcloud compute routers nats create $NAT_GATEWAY_NAME \ STARTUP_SCRIPT=$(cat <<'EOF' #!/bin/bash +# Update and upgrade the system apt update apt upgrade + +# Install Python 3 pip, Langflow, and Nginx apt install python3-pip pip install langflow apt-get install nginx + +# Configure Nginx for Langflow touch /etc/nginx/sites-available/langflow-app echo "server { listen 0.0.0.0:7860; @@ -75,6 +86,7 @@ EOF tempfile=$(mktemp) echo "$STARTUP_SCRIPT" > $tempfile +# Create the VM instance with the specified configuration and startup script gcloud compute instances create $VM_NAME \ --image-family $IMAGE_FAMILY \ --image-project $IMAGE_PROJECT \ @@ -88,6 +100,9 @@ gcloud compute instances create $VM_NAME \ rm $tempfile ``` +> This script sets up a Debian-based VM with the Langflow package, Nginx, and the necessary configurations to run the Langflow Dev environment. The VM will be accessible on TCP port 8080 from any IP address. + +
## Connecting to your new Langflow VM 1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page From 9274cb9ae0daa7f1e6e771af6e7e6aa6f1ee0b02 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Tue, 18 Apr 2023 04:29:42 +0000 Subject: [PATCH 21/73] check and create VPC and subnet --- GCP-SETUP.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/GCP-SETUP.md b/GCP-SETUP.md index 1f4eb6b4e..de0ec836d 100644 --- a/GCP-SETUP.md +++ b/GCP-SETUP.md @@ -14,20 +14,23 @@ ZONE="us-central1-a" REGION="us-central1" VPC_NAME="default" SUBNET_NAME="default" +SUBNET_RANGE="10.128.0.0/20" NAT_GATEWAY_NAME="nat-gateway" CLOUD_ROUTER_NAME="nat-client" # Set the GCP project's compute region gcloud config set compute/region $REGION -# Verify the VPC and subnet exist +# Check if the VPC exists, and create it if not vpc_exists=$(gcloud compute networks list --filter="name=$VPC_NAME" --format="value(name)") -subnet_exists=$(gcloud compute networks subnets list --filter="name=$SUBNET_NAME AND region=$REGION" --format="value(name)") +if [[ -z "$vpc_exists" ]]; then + gcloud compute networks create $VPC_NAME --subnet-mode=custom +fi -# Exit with an error message if the VPC or subnet does not exist -if [[ -z "$vpc_exists" || -z "$subnet_exists" ]]; then - echo "Error: VPC '$VPC_NAME' and/or subnet '$SUBNET_NAME' do not exist in region '$REGION'." - exit 1 +# Check if the subnet exists, and create it if not +subnet_exists=$(gcloud compute networks subnets list --filter="name=$SUBNET_NAME AND region=$REGION" --format="value(name)") +if [[ -z "$subnet_exists" ]]; then + gcloud compute networks subnets create $SUBNET_NAME --network=$VPC_NAME --region=$REGION --range=$SUBNET_RANGE fi # Create a firewall rule to allow TCP port 8080 for all instances in the VPC From b946edb3d12931bd9c43c659d73f34678bc51772 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Tue, 18 Apr 2023 04:32:41 +0000 Subject: [PATCH 22/73] Allow IAP --- GCP-SETUP.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/GCP-SETUP.md b/GCP-SETUP.md index de0ec836d..9261b8219 100644 --- a/GCP-SETUP.md +++ b/GCP-SETUP.md @@ -40,6 +40,12 @@ gcloud compute firewall-rules create allow-tcp-8080 \ --source-ranges 0.0.0.0/0 \ --direction INGRESS +# Create a firewall rule to allow IAP traffic +gcloud compute firewall-rules create allow-iap \ + --network $VPC_NAME \ + --allow tcp:80,tcp:443 \ + --source-ranges 35.235.240.0/20 \ + --direction INGRESS # Create the Cloud Router and NAT Gateway gcloud compute routers create $CLOUD_ROUTER_NAME \ From 5a51306153a90e4cce6245c0f63560798d946dde Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Tue, 18 Apr 2023 17:31:50 +0000 Subject: [PATCH 23/73] adding machine type to VM create --- GCP-SETUP.md | 1 + 1 file changed, 1 insertion(+) diff --git a/GCP-SETUP.md b/GCP-SETUP.md index 9261b8219..3a4750bc5 100644 --- a/GCP-SETUP.md +++ b/GCP-SETUP.md @@ -100,6 +100,7 @@ gcloud compute instances create $VM_NAME \ --image-family $IMAGE_FAMILY \ --image-project $IMAGE_PROJECT \ --boot-disk-size $BOOT_DISK_SIZE \ + --machine-type=n1-standard-4 \ --metadata-from-file startup-script=$tempfile \ --zone $ZONE \ --network $VPC_NAME \ From 19193d21e076e8290400713d34c963a7d2374ffc Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Wed, 19 Apr 2023 16:44:55 +0000 Subject: [PATCH 24/73] fix apt confirms, heredoc vars, add if statements --- GCP-SETUP.md | 53 +++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/GCP-SETUP.md b/GCP-SETUP.md index 3a4750bc5..3a0908ff2 100644 --- a/GCP-SETUP.md +++ b/GCP-SETUP.md @@ -34,57 +34,54 @@ if [[ -z "$subnet_exists" ]]; then fi # Create a firewall rule to allow TCP port 8080 for all instances in the VPC -gcloud compute firewall-rules create allow-tcp-8080 \ - --network $VPC_NAME \ - --allow tcp:8080 \ - --source-ranges 0.0.0.0/0 \ - --direction INGRESS +firewall_8080_exists=$(gcloud compute firewall-rules list --filter="name=allow-tcp-8080" --format="value(name)") +if [[ -z "$firewall_8080_exists" ]]; then + gcloud compute firewall-rules create allow-tcp-8080 --network $VPC_NAME --allow tcp:8080 --source-ranges 0.0.0.0/0 --direction INGRESS +fi # Create a firewall rule to allow IAP traffic -gcloud compute firewall-rules create allow-iap \ - --network $VPC_NAME \ - --allow tcp:80,tcp:443 \ - --source-ranges 35.235.240.0/20 \ - --direction INGRESS +firewall_iap_exists=$(gcloud compute firewall-rules list --filter="name=allow-iap" --format="value(name)") +if [[ -z "$firewall_iap_exists" ]]; then + gcloud compute firewall-rules create allow-iap --network $VPC_NAME --allow tcp:80,tcp:443 --source-ranges 35.235.240.0/20 --direction INGRESS +fi # Create the Cloud Router and NAT Gateway -gcloud compute routers create $CLOUD_ROUTER_NAME \ - --network $VPC_NAME \ - --region $REGION +cloud_router_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(name)") +if [[ -z "$cloud_router_exists" ]]; then + gcloud compute routers create $CLOUD_ROUTER_NAME --network $VPC_NAME --region $REGION +fi -gcloud compute routers nats create $NAT_GATEWAY_NAME \ - --router $CLOUD_ROUTER_NAME \ - --auto-allocate-nat-external-ips \ - --nat-all-subnet-ip-ranges \ - --enable-logging \ - --region $REGION +nat_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(nats.name)") +if [[ -z "$nat_exists" ]]; then + gcloud compute routers nats create $NAT_GATEWAY_NAME --router $CLOUD_ROUTER_NAME --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --enable-logging --region $REGION +fi # Define the startup script as a multiline Bash here-doc STARTUP_SCRIPT=$(cat <<'EOF' #!/bin/bash # Update and upgrade the system -apt update -apt upgrade +apt -y update +apt -y upgrade # Install Python 3 pip, Langflow, and Nginx -apt install python3-pip +apt -y install python3-pip pip install langflow -apt-get install nginx +apt-get -y install nginx # Configure Nginx for Langflow touch /etc/nginx/sites-available/langflow-app echo "server { - listen 0.0.0.0:7860; + listen 0.0.0.0:8080; location / { proxy_pass http://127.0.0.1:7860; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host "\$host"; + proxy_set_header X-Real-IP "\$remote_addr"; + proxy_set_header X-Forwarded-For "\$proxy_add_x_forwarded_for"; } }" >> /etc/nginx/sites-available/langflow-app -ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/ +ln -s /etc/nginx/sites-available/langflow-app /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl restart nginx langflow From ff3817903f752e09cacf151af71e17280379cc95 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:59:56 +0000 Subject: [PATCH 25/73] create setup files and GCP tutorial --- GCP-SETUP.md => GCP_DEPLOYMENT.md | 4 +++- scripts/gcp_setup.sh | 0 scripts/gcp_setup_tutorial.yaml | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) rename GCP-SETUP.md => GCP_DEPLOYMENT.md (93%) create mode 100644 scripts/gcp_setup.sh create mode 100644 scripts/gcp_setup_tutorial.yaml diff --git a/GCP-SETUP.md b/GCP_DEPLOYMENT.md similarity index 93% rename from GCP-SETUP.md rename to GCP_DEPLOYMENT.md index 3a0908ff2..015d02d6f 100644 --- a/GCP-SETUP.md +++ b/GCP_DEPLOYMENT.md @@ -1,6 +1,8 @@ -# Running Langflow from a new GCP project +# Running Langflow from a new Google Cloud project This guide will help you set up a Langflow Dev VM in a Google Cloud Platform project using Google Cloud Shell. +[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=gcp_setup_tutorial.yaml) + ## Run the following in your GCP cloudshell: diff --git a/scripts/gcp_setup.sh b/scripts/gcp_setup.sh new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/gcp_setup_tutorial.yaml b/scripts/gcp_setup_tutorial.yaml new file mode 100644 index 000000000..b45c56c30 --- /dev/null +++ b/scripts/gcp_setup_tutorial.yaml @@ -0,0 +1,10 @@ +title: Setting up Langflow on GCP +description: This tutorial guides you through setting up Langflow on GCP +steps: +- title: Running setup script + content: | + Running the setup script to create resources and deploy Langflow on GCP. + + ```bash + source gcp_setup.sh + ``` From 50b24f94437bff07e080172031d7070fde2cc33b Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 01:21:21 +0000 Subject: [PATCH 26/73] configure cloudshell to run walkthrough --- GCP_DEPLOYMENT.md | 2 +- README.md | 10 +++- scripts/gcp_setup.sh | 100 ++++++++++++++++++++++++++++++++ scripts/gcp_setup_tutorial.yaml | 86 ++++++++++++++++++++++++--- scripts/walkthroughtutorial.md | 78 +++++++++++++++++++++++++ 5 files changed, 266 insertions(+), 10 deletions(-) create mode 100644 scripts/walkthroughtutorial.md diff --git a/GCP_DEPLOYMENT.md b/GCP_DEPLOYMENT.md index 015d02d6f..3cf10df27 100644 --- a/GCP_DEPLOYMENT.md +++ b/GCP_DEPLOYMENT.md @@ -1,7 +1,7 @@ # Running Langflow from a new Google Cloud project This guide will help you set up a Langflow Dev VM in a Google Cloud Platform project using Google Cloud Shell. -[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=gcp_setup_tutorial.yaml) +[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=walkthroughtutorial.md) ## Run the following in your GCP cloudshell: diff --git a/README.md b/README.md index 970496349..eaaf84331 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ LangFlow is a GUI for [LangChain](https://github.com/hwchase17/langchain), designed with [react-flow](https://github.com/wbkd/react-flow) to provide an effortless way to experiment and prototype flows with drag-and-drop components and a chat box. ## 📦 Installation - +### Locally You can install LangFlow from pip: `pip install langflow` @@ -28,6 +28,14 @@ Next, run: `langflow` +### Deploy Langflow on Google Cloud Platform + +Follow our step-by-step guide to deploy Langflow on Google Cloud Platform (GCP) using Google Cloud Shell. The guide is available in the [Langflow in Google Cloud Platform](GCP_DEPLOYMENT.md) document. + +Alternatively, click the "Open in Cloud Shell" button below to launch Google Cloud Shell, clone the Langflow repository, and start an interactive tutorial that will guide you through the process of setting up the necessary resources and deploying Langflow on your GCP project. + +[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=GCP_SETUP_TUTORIAL.md) + ## 🎨 Creating Flows Creating flows with LangFlow is easy. Simply drag sidebar components onto the canvas and connect them together to create your pipeline. LangFlow provides a range of [LangChain components](https://langchain.readthedocs.io/en/latest/reference.html) to choose from, including LLMs, prompt serializers, agents, and chains. diff --git a/scripts/gcp_setup.sh b/scripts/gcp_setup.sh index e69de29bb..3e20e9589 100644 --- a/scripts/gcp_setup.sh +++ b/scripts/gcp_setup.sh @@ -0,0 +1,100 @@ +# Set the VM, image, and networking configuration +VM_NAME="langflow-dev" +IMAGE_FAMILY="debian-11" +IMAGE_PROJECT="debian-cloud" +BOOT_DISK_SIZE="100GB" +ZONE="us-central1-a" +REGION="us-central1" +VPC_NAME="default" +SUBNET_NAME="default" +SUBNET_RANGE="10.128.0.0/20" +NAT_GATEWAY_NAME="nat-gateway" +CLOUD_ROUTER_NAME="nat-client" + +# Set the GCP project's compute region +gcloud config set compute/region $REGION + +# Check if the VPC exists, and create it if not +vpc_exists=$(gcloud compute networks list --filter="name=$VPC_NAME" --format="value(name)") +if [[ -z "$vpc_exists" ]]; then + gcloud compute networks create $VPC_NAME --subnet-mode=custom +fi + +# Check if the subnet exists, and create it if not +subnet_exists=$(gcloud compute networks subnets list --filter="name=$SUBNET_NAME AND region=$REGION" --format="value(name)") +if [[ -z "$subnet_exists" ]]; then + gcloud compute networks subnets create $SUBNET_NAME --network=$VPC_NAME --region=$REGION --range=$SUBNET_RANGE +fi + +# Create a firewall rule to allow TCP port 8080 for all instances in the VPC +firewall_8080_exists=$(gcloud compute firewall-rules list --filter="name=allow-tcp-8080" --format="value(name)") +if [[ -z "$firewall_8080_exists" ]]; then + gcloud compute firewall-rules create allow-tcp-8080 --network $VPC_NAME --allow tcp:8080 --source-ranges 0.0.0.0/0 --direction INGRESS +fi + +# Create a firewall rule to allow IAP traffic +firewall_iap_exists=$(gcloud compute firewall-rules list --filter="name=allow-iap" --format="value(name)") +if [[ -z "$firewall_iap_exists" ]]; then + gcloud compute firewall-rules create allow-iap --network $VPC_NAME --allow tcp:80,tcp:443 --source-ranges 35.235.240.0/20 --direction INGRESS +fi + +# Create the Cloud Router and NAT Gateway +cloud_router_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(name)") +if [[ -z "$cloud_router_exists" ]]; then + gcloud compute routers create $CLOUD_ROUTER_NAME --network $VPC_NAME --region $REGION +fi + +nat_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(nats.name)") +if [[ -z "$nat_exists" ]]; then + gcloud compute routers nats create $NAT_GATEWAY_NAME --router $CLOUD_ROUTER_NAME --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --enable-logging --region $REGION +fi + +# Define the startup script as a multiline Bash here-doc +STARTUP_SCRIPT=$(cat <<'EOF' +#!/bin/bash + +# Update and upgrade the system +apt -y update +apt -y upgrade + +# Install Python 3 pip, Langflow, and Nginx +apt -y install python3-pip +pip install langflow +apt-get -y install nginx + +# Configure Nginx for Langflow +touch /etc/nginx/sites-available/langflow-app +echo "server { + listen 0.0.0.0:8080; + + location / { + proxy_pass http://127.0.0.1:7860; + proxy_set_header Host "\$host"; + proxy_set_header X-Real-IP "\$remote_addr"; + proxy_set_header X-Forwarded-For "\$proxy_add_x_forwarded_for"; + } +}" >> /etc/nginx/sites-available/langflow-app +ln -s /etc/nginx/sites-available/langflow-app /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl restart nginx +langflow +EOF +) + +# Create a temporary file to store the startup script +tempfile=$(mktemp) +echo "$STARTUP_SCRIPT" > $tempfile + +# Create the VM instance with the specified configuration and startup script +gcloud compute instances create $VM_NAME \ + --image-family $IMAGE_FAMILY \ + --image-project $IMAGE_PROJECT \ + --boot-disk-size $BOOT_DISK_SIZE \ + --machine-type=n1-standard-4 \ + --metadata-from-file startup-script=$tempfile \ + --zone $ZONE \ + --network $VPC_NAME \ + --subnet $SUBNET_NAME + +# Remove the temporary file after the VM is created +rm $tempfile diff --git a/scripts/gcp_setup_tutorial.yaml b/scripts/gcp_setup_tutorial.yaml index b45c56c30..f8c5b401c 100644 --- a/scripts/gcp_setup_tutorial.yaml +++ b/scripts/gcp_setup_tutorial.yaml @@ -1,10 +1,80 @@ -title: Setting up Langflow on GCP -description: This tutorial guides you through setting up Langflow on GCP -steps: -- title: Running setup script - content: | - Running the setup script to create resources and deploy Langflow on GCP. +title: Deploy Langflow on Google Cloud Platform +duration: 45m +author: Your Name +environment: + cwd: working_dir + repo: + url: https://github.com/genome21/langflow + working_dir: scripts + +steps: +- title: Introduction + content: | + In this tutorial, you will learn how to deploy Langflow on Google Cloud Platform (GCP) using Google Cloud Shell. + + This tutorial assumes you have a GCP account and basic knowledge of Google Cloud Shell. If you're not familiar with Cloud Shell, you can review the [Cloud Shell documentation](https://cloud.google.com/shell/docs). + +- title: Set up your environment + content: | + Before you start, make sure you have the following prerequisites: + + - A GCP account with the necessary permissions to create resources + - A project on GCP where you want to deploy Langflow + + + + In the next step, you'll clone the Langflow repository and navigate to the `scripts` directory. + +- title: Clone the repository and navigate to the scripts directory + content: | + Run the following commands to clone the Langflow repository and navigate to the `scripts` directory: - ```bash - source gcp_setup.sh ``` + git clone https://github.com/genome21/langflow + cd langflow/scripts + ``` + + In the next step, you'll configure the GCP environment and deploy Langflow. + +- title: Configure the GCP environment and deploy Langflow + content: | + Run the `deploy_langflow_gcp.sh` script to configure the GCP environment and deploy Langflow: + + ``` + ./deploy_langflow_gcp.sh + ``` + + The script will: + + 1. Check if the required resources (VPC, subnet, firewall rules, and Cloud Router) exist and create them if needed + 2. Create a startup script to install Python, Langflow, and Nginx + 3. Create a Compute Engine VM instance with the specified configuration and startup script + 4. Configure Nginx to serve Langflow on TCP port 8080 + + In the next step, you'll learn how to connect to the Langflow VM. + +- title: Connect to the Langflow VM + content: | + To connect to your new Langflow VM, follow these steps: + + 1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page + 2. Click on the external IP for your VM + 3. Add port 8080 (assuming your VM external IP is 192.168.0.1): + http://192.168.0.1:8080 + 4. You will be greeted by the Langflow Dev environment + + Congratulations! You have successfully deployed Langflow on Google Cloud Platform. + +- title: Cleanup + content: | + If you want to remove the resources created during this tutorial, you can use the following commands: + + ``` + gcloud compute instances delete langflow-dev --zone us-central1-a --quiet + gcloud compute routers nats delete nat-gateway --router nat-client --region us-central1 --quiet + gcloud compute routers delete nat-client --region us-central1 --quiet + gcloud compute firewall-rules delete allow-tcp-8080 --quiet + gcloud compute firewall-rules delete allow-iap --quiet + gcloud compute networks subnets delete default --region us-central1 --quiet + gcloud compute networks delete default --quiet + `` diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md new file mode 100644 index 000000000..ebc9a4b95 --- /dev/null +++ b/scripts/walkthroughtutorial.md @@ -0,0 +1,78 @@ +# Deploy Langflow on Google Cloud Platform + +**Duration**: 45 minutes +**Author**: [Robert Wilkins III](https://www.linkedin.com/in/robertwilkinsiii) + +## Introduction + +In this tutorial, you will learn how to deploy Langflow on [Google Cloud Platform](https://cloud.google.com/) (GCP) using Google Cloud Shell. + +This tutorial assumes you have a GCP account and basic knowledge of Google Cloud Shell. If you're not familiar with Cloud Shell, you can review the [Cloud Shell documentation](https://cloud.google.com/shell/docs). + +## Set up your environment + +Before you start, make sure you have the following prerequisites: + +- A GCP account with the necessary permissions to create resources +- A project on GCP where you want to deploy Langflow + +[**Select your GCP project**] + +In the next step, you'll clone the Langflow repository and navigate to the `scripts` directory. + +## Clone the repository and navigate to the scripts directory + +Run the following commands to clone the Langflow repository and navigate to the `scripts` directory: + +```bash +git clone https://github.com/genome21/langflow +cd langflow/scripts +``` + +In the next step, you'll configure the GCP environment and deploy Langflow. + +## Configure the GCP environment and deploy Langflow +Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: + +```bash +./deploy_langflow_gcp.sh +``` + +The script will: + +1. Check if the required resources (VPC, subnet, firewall rules, and Cloud Router) exist and create them if needed +2. Create a startup script to install Python, Langflow, and Nginx +3. Create a Compute Engine VM instance with the specified configuration and startup script +4. Configure Nginx to serve Langflow on TCP port 8080 + +In the next step, you'll learn how to connect to the Langflow VM. + +## Connect to the Langflow VM +To connect to your new Langflow VM, follow these steps: + +1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page +2. Click on the external IP for your VM +3. Add port 8080 (assuming your VM external IP is 192.168.0.1): +http://192.168.0.1:8080 +4. You will be greeted by the Langflow Dev environment + +Congratulations! You have successfully deployed Langflow on Google Cloud Platform. + +## Cleanup +If you want to remove the resources created during this tutorial, you can use the following commands: + +```sql +gcloud compute instances delete langflow-dev --zone us-central1-a --quiet + +gcloud compute routers nats delete nat-gateway --router nat-client --region us-central1 --quiet + +gcloud compute routers delete nat-client --region us-central1 --quiet + +gcloud compute firewall-rules delete allow-tcp-8080 --quiet + +gcloud compute firewall-rules delete allow-iap --quiet + +gcloud compute networks subnets delete default --region us-central1 --quiet + +gcloud compute networks delete default --quiet +``` From aeabaa32cd3fbd84d9d48f2ef876edfa34f5b2eb Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 01:30:44 +0000 Subject: [PATCH 27/73] remove scripted steps from walkthrough --- scripts/walkthroughtutorial.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index ebc9a4b95..641cce1e8 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -18,16 +18,16 @@ Before you start, make sure you have the following prerequisites: [**Select your GCP project**] -In the next step, you'll clone the Langflow repository and navigate to the `scripts` directory. +[comment]: <> (In the next step, you'll clone the Langflow repository and navigate to the `scripts` directory.) -## Clone the repository and navigate to the scripts directory +[comment]: <> (## Clone the repository and navigate to the scripts directory) -Run the following commands to clone the Langflow repository and navigate to the `scripts` directory: +[comment]: <> (Run the following commands to clone the Langflow repository and navigate to the `scripts` directory:) -```bash -git clone https://github.com/genome21/langflow -cd langflow/scripts -``` +[comment]: <> (```bash) +[comment]: <> (git clone https://github.com/genome21/langflow) +[comment]: <> (cd langflow/scripts) +[comment]: <> (```) In the next step, you'll configure the GCP environment and deploy Langflow. From e5aece49bfdfa1f13bb907dc11884ddf5f0e6a34 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 01:32:45 +0000 Subject: [PATCH 28/73] remove comments that show up in walkthrough --- scripts/walkthroughtutorial.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 641cce1e8..d21dbd31a 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -18,17 +18,6 @@ Before you start, make sure you have the following prerequisites: [**Select your GCP project**] -[comment]: <> (In the next step, you'll clone the Langflow repository and navigate to the `scripts` directory.) - -[comment]: <> (## Clone the repository and navigate to the scripts directory) - -[comment]: <> (Run the following commands to clone the Langflow repository and navigate to the `scripts` directory:) - -[comment]: <> (```bash) -[comment]: <> (git clone https://github.com/genome21/langflow) -[comment]: <> (cd langflow/scripts) -[comment]: <> (```) - In the next step, you'll configure the GCP environment and deploy Langflow. ## Configure the GCP environment and deploy Langflow From bfdbabed55ab2ce1ad570d6c95553890c63df9bb Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 01:35:20 +0000 Subject: [PATCH 29/73] fix bash command launch --- scripts/walkthroughtutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index d21dbd31a..153a5a0c2 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -24,7 +24,7 @@ In the next step, you'll configure the GCP environment and deploy Langflow. Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: ```bash -./deploy_langflow_gcp.sh +bash ./deploy_langflow_gcp.sh ``` The script will: From 9a06ff54c7eb9e7be43af3fcff66f7e753531a2e Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 01:37:52 +0000 Subject: [PATCH 30/73] match bash script to walkthrough --- scripts/{gcp_setup.sh => deploy_langflow_gcp.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/{gcp_setup.sh => deploy_langflow_gcp.sh} (100%) diff --git a/scripts/gcp_setup.sh b/scripts/deploy_langflow_gcp.sh similarity index 100% rename from scripts/gcp_setup.sh rename to scripts/deploy_langflow_gcp.sh From 08a1739fa775b6b79ddd921033d9b5e8c51e836f Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 01:55:34 +0000 Subject: [PATCH 31/73] force gcp login in ephemeral cloudshell --- scripts/walkthroughtutorial.md | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 153a5a0c2..99599010f 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -24,6 +24,7 @@ In the next step, you'll configure the GCP environment and deploy Langflow. Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: ```bash +gcloud auth login --brief --quiet bash ./deploy_langflow_gcp.sh ``` From 9c9b69db596d05d0a7aab63b1d127000783171a1 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 02:05:34 +0000 Subject: [PATCH 32/73] add cloudshell repo trust advisory --- GCP_DEPLOYMENT.md | 1 + 1 file changed, 1 insertion(+) diff --git a/GCP_DEPLOYMENT.md b/GCP_DEPLOYMENT.md index 3cf10df27..6bbd54097 100644 --- a/GCP_DEPLOYMENT.md +++ b/GCP_DEPLOYMENT.md @@ -1,5 +1,6 @@ # Running Langflow from a new Google Cloud project This guide will help you set up a Langflow Dev VM in a Google Cloud Platform project using Google Cloud Shell. +> When cloudshell opens, select **Trust this repo**. Some gcloud commands do not run in ephemeral cloudshell. [![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=walkthroughtutorial.md) From 98be8f87e4ef22c534483ac84f2210047afa9f5e Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 02:07:10 +0000 Subject: [PATCH 33/73] remove login prompt for ephemeral cloudshell --- scripts/walkthroughtutorial.md | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 99599010f..153a5a0c2 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -24,7 +24,6 @@ In the next step, you'll configure the GCP environment and deploy Langflow. Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: ```bash -gcloud auth login --brief --quiet bash ./deploy_langflow_gcp.sh ``` From 6efa1b737741f8a6983c38617bb1a59f97ae7779 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 02:10:45 +0000 Subject: [PATCH 34/73] set project config --- scripts/walkthroughtutorial.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 153a5a0c2..f908bce3b 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -23,7 +23,8 @@ In the next step, you'll configure the GCP environment and deploy Langflow. ## Configure the GCP environment and deploy Langflow Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: -```bash +```sh +gcloud config set project {{project-id}} bash ./deploy_langflow_gcp.sh ``` From 7ef97e13347bab8315aee08f69e109f1ffb36d8c Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 02:18:27 +0000 Subject: [PATCH 35/73] testing var expansion --- scripts/walkthroughtutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index f908bce3b..d30c3b702 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -16,7 +16,7 @@ Before you start, make sure you have the following prerequisites: - A GCP account with the necessary permissions to create resources - A project on GCP where you want to deploy Langflow -[**Select your GCP project**] +[**Select your GCP project**] In the next step, you'll configure the GCP environment and deploy Langflow. @@ -24,7 +24,7 @@ In the next step, you'll configure the GCP environment and deploy Langflow. Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: ```sh -gcloud config set project {{project-id}} +gcloud config set project {{project_id}} bash ./deploy_langflow_gcp.sh ``` From 90633c3915793cc34b699a0a5fea2f6cb2a5d556 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 02:19:36 +0000 Subject: [PATCH 36/73] revert var expansion test --- scripts/walkthroughtutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index d30c3b702..3b7e3a76e 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -24,7 +24,7 @@ In the next step, you'll configure the GCP environment and deploy Langflow. Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: ```sh -gcloud config set project {{project_id}} +gcloud config set project {{project-id}} bash ./deploy_langflow_gcp.sh ``` From c4ebb0a3f68faba6a951d40f872a68f9b8355a33 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 02:23:34 +0000 Subject: [PATCH 37/73] var expansion again --- scripts/walkthroughtutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 3b7e3a76e..d30c3b702 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -24,7 +24,7 @@ In the next step, you'll configure the GCP environment and deploy Langflow. Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: ```sh -gcloud config set project {{project-id}} +gcloud config set project {{project_id}} bash ./deploy_langflow_gcp.sh ``` From b54b0f0904f46cc8278512909a6c88200b26a14c Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 02:33:47 +0000 Subject: [PATCH 38/73] var expansion alt test --- scripts/walkthroughtutorial.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index d30c3b702..66efe5e74 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -16,7 +16,11 @@ Before you start, make sure you have the following prerequisites: - A GCP account with the necessary permissions to create resources - A project on GCP where you want to deploy Langflow -[**Select your GCP project**] +[**Select your GCP project**] + + In the next step, you'll configure the GCP environment and deploy Langflow. @@ -24,7 +28,7 @@ In the next step, you'll configure the GCP environment and deploy Langflow. Run the deploy_langflow_gcp.sh script to configure the GCP environment and deploy Langflow: ```sh -gcloud config set project {{project_id}} +gcloud config set project bash ./deploy_langflow_gcp.sh ``` From d310a8172f6a2a9fc167ee76e5ac8c1552141f53 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 02:57:37 +0000 Subject: [PATCH 39/73] provide user with link to langflow server --- scripts/walkthroughtutorial.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 66efe5e74..0f65dbadf 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -46,8 +46,16 @@ To connect to your new Langflow VM, follow these steps: 1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page 2. Click on the external IP for your VM -3. Add port 8080 (assuming your VM external IP is 192.168.0.1): -http://192.168.0.1:8080 +
or +3. Run the following command to store the VM's IP in a variable called `LANGFLOW-IP`: +```bash +export LANGFLOW-IP=$(gcloud compute instances list --filter="NAME=langflow-dev" --format="value(EXTERNAL_IP)") + +echo http://$LANGFLOW-IP:8080 +``` + + + 4. You will be greeted by the Langflow Dev environment Congratulations! You have successfully deployed Langflow on Google Cloud Platform. From f46e27d1f0d987d99499bbb0671bac06e2384014 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:08:50 +0000 Subject: [PATCH 40/73] vars and trophies --- scripts/walkthroughtutorial.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 0f65dbadf..5398617c3 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -42,6 +42,7 @@ The script will: In the next step, you'll learn how to connect to the Langflow VM. ## Connect to the Langflow VM + To connect to your new Langflow VM, follow these steps: 1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page @@ -54,7 +55,7 @@ export LANGFLOW-IP=$(gcloud compute instances list --filter="NAME=langflow-dev" echo http://$LANGFLOW-IP:8080 ``` - + 4. You will be greeted by the Langflow Dev environment From b9a0e55d43355600f7993ccf0f45220bc2ef0ee3 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:11:30 +0000 Subject: [PATCH 41/73] remove input tag --- scripts/walkthroughtutorial.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 5398617c3..2711ccd93 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -50,13 +50,11 @@ To connect to your new Langflow VM, follow these steps:
or 3. Run the following command to store the VM's IP in a variable called `LANGFLOW-IP`: ```bash -export LANGFLOW-IP=$(gcloud compute instances list --filter="NAME=langflow-dev" --format="value(EXTERNAL_IP)") +export LANGFLOW_IP=$(gcloud compute instances list --filter="NAME=langflow-dev" --format="value(EXTERNAL_IP)") -echo http://$LANGFLOW-IP:8080 +echo http://$LANGFLOW_IP:8080 ``` - - 4. You will be greeted by the Langflow Dev environment Congratulations! You have successfully deployed Langflow on Google Cloud Platform. From 37bdafa9db6bf1717280f38a4aaef8b5b89d1459 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:17:40 +0000 Subject: [PATCH 42/73] clarify notes to connect to vm --- scripts/walkthroughtutorial.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 2711ccd93..dd107a770 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -45,17 +45,16 @@ In the next step, you'll learn how to connect to the Langflow VM. To connect to your new Langflow VM, follow these steps: -1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page -2. Click on the external IP for your VM -
or -3. Run the following command to store the VM's IP in a variable called `LANGFLOW-IP`: +1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page and click on the external IP for your VM. Make sure to use HTTP and set the port to 8080 +
**or** +3. Run the following command to display the URL for your Langflow environment: ```bash export LANGFLOW_IP=$(gcloud compute instances list --filter="NAME=langflow-dev" --format="value(EXTERNAL_IP)") echo http://$LANGFLOW_IP:8080 ``` -4. You will be greeted by the Langflow Dev environment +4. Click on the Langflow URL in cloudshell to be greeted by the Langflow Dev environment Congratulations! You have successfully deployed Langflow on Google Cloud Platform. From 5a7072175f2b63491ea1fbafcc23243c03780aeb Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:20:09 +0000 Subject: [PATCH 43/73] move trophy toward end of walkthrough --- scripts/walkthroughtutorial.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index dd107a770..7742f3453 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -42,7 +42,6 @@ The script will: In the next step, you'll learn how to connect to the Langflow VM. ## Connect to the Langflow VM - To connect to your new Langflow VM, follow these steps: 1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page and click on the external IP for your VM. Make sure to use HTTP and set the port to 8080 @@ -58,6 +57,8 @@ echo http://$LANGFLOW_IP:8080 Congratulations! You have successfully deployed Langflow on Google Cloud Platform. + + ## Cleanup If you want to remove the resources created during this tutorial, you can use the following commands: From 57d83740f1a8bd5f488af36d28e9419568fb4c08 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:29:03 +0000 Subject: [PATCH 44/73] improve readability --- scripts/walkthroughtutorial.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 7742f3453..3d9401f2e 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -69,6 +69,13 @@ gcloud compute routers nats delete nat-gateway --router nat-client --region us-c gcloud compute routers delete nat-client --region us-central1 --quiet +``` +The following network settings and services are used during this walkthrough. If you plan to continue using the project after the walkthrough, you may keep these configurations in place. + +However, if you decide to remove them after completing the walkthrough, you can use the following gcloud commands: +> These commands will delete the firewall rules and network configurations created during the walkthrough. Make sure to run them only if you no longer need these settings. + +``` gcloud compute firewall-rules delete allow-tcp-8080 --quiet gcloud compute firewall-rules delete allow-iap --quiet From 56e4ae1fcd4410e07abc2a86692f0db184e8d416 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:35:10 +0000 Subject: [PATCH 45/73] add styling --- scripts/walkthroughtutorial.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 3d9401f2e..3731533c1 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -39,6 +39,8 @@ The script will: 3. Create a Compute Engine VM instance with the specified configuration and startup script 4. Configure Nginx to serve Langflow on TCP port 8080 +> The process may take approximately 30 minutes to complete. Rest assured that progress is being made, and you'll be able to proceed once the process is finished. + In the next step, you'll learn how to connect to the Langflow VM. ## Connect to the Langflow VM From b6ae41eef079ce7114e6e87503b99236bbfc2712 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:36:27 +0000 Subject: [PATCH 46/73] more styling --- scripts/walkthroughtutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 3731533c1..b53d3c6d2 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -39,7 +39,7 @@ The script will: 3. Create a Compute Engine VM instance with the specified configuration and startup script 4. Configure Nginx to serve Langflow on TCP port 8080 -> The process may take approximately 30 minutes to complete. Rest assured that progress is being made, and you'll be able to proceed once the process is finished. +> The process may take approximately 30 minutes to complete. Rest assured that progress is being made, and you'll be able to proceed once the process is finished. In the next step, you'll learn how to connect to the Langflow VM. @@ -75,7 +75,7 @@ gcloud compute routers delete nat-client --region us-central1 --quiet The following network settings and services are used during this walkthrough. If you plan to continue using the project after the walkthrough, you may keep these configurations in place. However, if you decide to remove them after completing the walkthrough, you can use the following gcloud commands: -> These commands will delete the firewall rules and network configurations created during the walkthrough. Make sure to run them only if you no longer need these settings. +> These commands will delete the firewall rules and network configurations created during the walkthrough. Make sure to run them only if you no longer need these settings. ``` gcloud compute firewall-rules delete allow-tcp-8080 --quiet From 6a59d64a0d44b3f56d6c00873f5281642b8ac3c0 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:54:58 +0000 Subject: [PATCH 47/73] remove redundant wording --- GCP_DEPLOYMENT.md | 119 +------------------------------- scripts/gcp_setup_tutorial.yaml | 80 --------------------- 2 files changed, 2 insertions(+), 197 deletions(-) delete mode 100644 scripts/gcp_setup_tutorial.yaml diff --git a/GCP_DEPLOYMENT.md b/GCP_DEPLOYMENT.md index 6bbd54097..01686e4ed 100644 --- a/GCP_DEPLOYMENT.md +++ b/GCP_DEPLOYMENT.md @@ -1,122 +1,7 @@ # Running Langflow from a new Google Cloud project This guide will help you set up a Langflow Dev VM in a Google Cloud Platform project using Google Cloud Shell. -> When cloudshell opens, select **Trust this repo**. Some gcloud commands do not run in ephemeral cloudshell. +> When cloudshell opens, select **Trust repo**. Some gcloud commands do not run in ephemeral cloudshell. [![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=walkthroughtutorial.md) - -## Run the following in your GCP cloudshell: - -```bash -# Set the VM, image, and networking configuration -VM_NAME="langflow-dev" -IMAGE_FAMILY="debian-11" -IMAGE_PROJECT="debian-cloud" -BOOT_DISK_SIZE="100GB" -ZONE="us-central1-a" -REGION="us-central1" -VPC_NAME="default" -SUBNET_NAME="default" -SUBNET_RANGE="10.128.0.0/20" -NAT_GATEWAY_NAME="nat-gateway" -CLOUD_ROUTER_NAME="nat-client" - -# Set the GCP project's compute region -gcloud config set compute/region $REGION - -# Check if the VPC exists, and create it if not -vpc_exists=$(gcloud compute networks list --filter="name=$VPC_NAME" --format="value(name)") -if [[ -z "$vpc_exists" ]]; then - gcloud compute networks create $VPC_NAME --subnet-mode=custom -fi - -# Check if the subnet exists, and create it if not -subnet_exists=$(gcloud compute networks subnets list --filter="name=$SUBNET_NAME AND region=$REGION" --format="value(name)") -if [[ -z "$subnet_exists" ]]; then - gcloud compute networks subnets create $SUBNET_NAME --network=$VPC_NAME --region=$REGION --range=$SUBNET_RANGE -fi - -# Create a firewall rule to allow TCP port 8080 for all instances in the VPC -firewall_8080_exists=$(gcloud compute firewall-rules list --filter="name=allow-tcp-8080" --format="value(name)") -if [[ -z "$firewall_8080_exists" ]]; then - gcloud compute firewall-rules create allow-tcp-8080 --network $VPC_NAME --allow tcp:8080 --source-ranges 0.0.0.0/0 --direction INGRESS -fi - -# Create a firewall rule to allow IAP traffic -firewall_iap_exists=$(gcloud compute firewall-rules list --filter="name=allow-iap" --format="value(name)") -if [[ -z "$firewall_iap_exists" ]]; then - gcloud compute firewall-rules create allow-iap --network $VPC_NAME --allow tcp:80,tcp:443 --source-ranges 35.235.240.0/20 --direction INGRESS -fi - -# Create the Cloud Router and NAT Gateway -cloud_router_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(name)") -if [[ -z "$cloud_router_exists" ]]; then - gcloud compute routers create $CLOUD_ROUTER_NAME --network $VPC_NAME --region $REGION -fi - -nat_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(nats.name)") -if [[ -z "$nat_exists" ]]; then - gcloud compute routers nats create $NAT_GATEWAY_NAME --router $CLOUD_ROUTER_NAME --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --enable-logging --region $REGION -fi - -# Define the startup script as a multiline Bash here-doc -STARTUP_SCRIPT=$(cat <<'EOF' -#!/bin/bash - -# Update and upgrade the system -apt -y update -apt -y upgrade - -# Install Python 3 pip, Langflow, and Nginx -apt -y install python3-pip -pip install langflow -apt-get -y install nginx - -# Configure Nginx for Langflow -touch /etc/nginx/sites-available/langflow-app -echo "server { - listen 0.0.0.0:8080; - - location / { - proxy_pass http://127.0.0.1:7860; - proxy_set_header Host "\$host"; - proxy_set_header X-Real-IP "\$remote_addr"; - proxy_set_header X-Forwarded-For "\$proxy_add_x_forwarded_for"; - } -}" >> /etc/nginx/sites-available/langflow-app -ln -s /etc/nginx/sites-available/langflow-app /etc/nginx/sites-enabled/ -sudo nginx -t -sudo systemctl restart nginx -langflow -EOF -) - -# Create a temporary file to store the startup script -tempfile=$(mktemp) -echo "$STARTUP_SCRIPT" > $tempfile - -# Create the VM instance with the specified configuration and startup script -gcloud compute instances create $VM_NAME \ - --image-family $IMAGE_FAMILY \ - --image-project $IMAGE_PROJECT \ - --boot-disk-size $BOOT_DISK_SIZE \ - --machine-type=n1-standard-4 \ - --metadata-from-file startup-script=$tempfile \ - --zone $ZONE \ - --network $VPC_NAME \ - --subnet $SUBNET_NAME - -# Remove the temporary file after the VM is created -rm $tempfile - -``` -> This script sets up a Debian-based VM with the Langflow package, Nginx, and the necessary configurations to run the Langflow Dev environment. The VM will be accessible on TCP port 8080 from any IP address. - -
- -## Connecting to your new Langflow VM -1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page -2. Click on the external IP for your VM -3. Add port 8080 (assuming your VM external IP is 192.168.0.1): -http://192.168.0.1:8080 -4. You will be greeted by the Langflow Dev environment \ No newline at end of file +This script sets up a Debian-based VM with the Langflow package, Nginx, and the necessary configurations to run the Langflow Dev environment. \ No newline at end of file diff --git a/scripts/gcp_setup_tutorial.yaml b/scripts/gcp_setup_tutorial.yaml deleted file mode 100644 index f8c5b401c..000000000 --- a/scripts/gcp_setup_tutorial.yaml +++ /dev/null @@ -1,80 +0,0 @@ -title: Deploy Langflow on Google Cloud Platform -duration: 45m -author: Your Name -environment: - cwd: working_dir - repo: - url: https://github.com/genome21/langflow - working_dir: scripts - -steps: -- title: Introduction - content: | - In this tutorial, you will learn how to deploy Langflow on Google Cloud Platform (GCP) using Google Cloud Shell. - - This tutorial assumes you have a GCP account and basic knowledge of Google Cloud Shell. If you're not familiar with Cloud Shell, you can review the [Cloud Shell documentation](https://cloud.google.com/shell/docs). - -- title: Set up your environment - content: | - Before you start, make sure you have the following prerequisites: - - - A GCP account with the necessary permissions to create resources - - A project on GCP where you want to deploy Langflow - - - - In the next step, you'll clone the Langflow repository and navigate to the `scripts` directory. - -- title: Clone the repository and navigate to the scripts directory - content: | - Run the following commands to clone the Langflow repository and navigate to the `scripts` directory: - - ``` - git clone https://github.com/genome21/langflow - cd langflow/scripts - ``` - - In the next step, you'll configure the GCP environment and deploy Langflow. - -- title: Configure the GCP environment and deploy Langflow - content: | - Run the `deploy_langflow_gcp.sh` script to configure the GCP environment and deploy Langflow: - - ``` - ./deploy_langflow_gcp.sh - ``` - - The script will: - - 1. Check if the required resources (VPC, subnet, firewall rules, and Cloud Router) exist and create them if needed - 2. Create a startup script to install Python, Langflow, and Nginx - 3. Create a Compute Engine VM instance with the specified configuration and startup script - 4. Configure Nginx to serve Langflow on TCP port 8080 - - In the next step, you'll learn how to connect to the Langflow VM. - -- title: Connect to the Langflow VM - content: | - To connect to your new Langflow VM, follow these steps: - - 1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page - 2. Click on the external IP for your VM - 3. Add port 8080 (assuming your VM external IP is 192.168.0.1): - http://192.168.0.1:8080 - 4. You will be greeted by the Langflow Dev environment - - Congratulations! You have successfully deployed Langflow on Google Cloud Platform. - -- title: Cleanup - content: | - If you want to remove the resources created during this tutorial, you can use the following commands: - - ``` - gcloud compute instances delete langflow-dev --zone us-central1-a --quiet - gcloud compute routers nats delete nat-gateway --router nat-client --region us-central1 --quiet - gcloud compute routers delete nat-client --region us-central1 --quiet - gcloud compute firewall-rules delete allow-tcp-8080 --quiet - gcloud compute firewall-rules delete allow-iap --quiet - gcloud compute networks subnets delete default --region us-central1 --quiet - gcloud compute networks delete default --quiet - `` From dada24a5e66ff72a7336ac2a34e7b86305922be4 Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 04:43:26 +0000 Subject: [PATCH 48/73] add spot instance support and pricing --- GCP_DEPLOYMENT.md | 31 +++++++-- scripts/deploy_langflow_gcp_spot.sh | 101 ++++++++++++++++++++++++++++ scripts/walkthroughtutorial.md | 7 +- scripts/walkthroughtutorial_spot.md | 88 ++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 scripts/deploy_langflow_gcp_spot.sh create mode 100644 scripts/walkthroughtutorial_spot.md diff --git a/GCP_DEPLOYMENT.md b/GCP_DEPLOYMENT.md index 01686e4ed..0491dabb0 100644 --- a/GCP_DEPLOYMENT.md +++ b/GCP_DEPLOYMENT.md @@ -1,7 +1,30 @@ -# Running Langflow from a new Google Cloud project -This guide will help you set up a Langflow Dev VM in a Google Cloud Platform project using Google Cloud Shell. -> When cloudshell opens, select **Trust repo**. Some gcloud commands do not run in ephemeral cloudshell. +# Run Langflow from a New Google Cloud Project +This guide will help you set up a Langflow development VM in a Google Cloud Platform project using Google Cloud Shell. + +> **Note**: When Cloud Shell opens, be sure to select **Trust repo**. Some `gcloud` commands might not run in an ephemeral Cloud Shell environment. + + +## Standard VM [![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=walkthroughtutorial.md) -This script sets up a Debian-based VM with the Langflow package, Nginx, and the necessary configurations to run the Langflow Dev environment. \ No newline at end of file +This script sets up a Debian-based VM with the Langflow package, Nginx, and the necessary configurations to run the Langflow Dev environment. +
+ +## Spot/Preemptible Instance + +[![Open in Cloud Shell - Spot Instance](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=walkthroughtutorial.md) + +When running as a [spot (preemptible) instance](https://cloud.google.com/compute/docs/instances/preemptible), the code and VM will behave the same way as in a regular instance, executing the startup script to configure the environment, install necessary dependencies, and run the Langflow application. However, **due to the nature of spot instances, the VM may be terminated at any time if Google Cloud needs to reclaim the resources**. This makes spot instances suitable for fault-tolerant, stateless, or interruptible workloads that can handle unexpected terminations and restarts. + +## Pricing +
+ +| Component | Regular Cost (Hourly) | Regular Cost (Monthly) | Spot/Preemptible Cost (Hourly) | Spot/Preemptible Cost (Monthly) | Notes | +| -------------- | --------------------- | ---------------------- | ------------------------------ | ------------------------------- | ----- | +| 100 GB Disk | - | $10/month | - | $10/month | Disk cost remains the same for both regular and Spot/Preemptible VMs | +| VM (n1-standard-4) | $0.15/hr | ~$108/month | ~$0.04/hr | ~$29/month | The VM cost can be significantly reduced using a Spot/Preemptible instance | +| **Total** | **$0.15/hr** | **~$118/month** | **~$0.04/hr** | **~$39/month** | Total costs for running the VM and disk 24/7 for an entire month | + +> For a more accurate breakdown of costs, please use the [**GCP Pricing Calculator**](https://cloud.google.com/products/calculator) + diff --git a/scripts/deploy_langflow_gcp_spot.sh b/scripts/deploy_langflow_gcp_spot.sh new file mode 100644 index 000000000..7ddc93b96 --- /dev/null +++ b/scripts/deploy_langflow_gcp_spot.sh @@ -0,0 +1,101 @@ +# Set the VM, image, and networking configuration +VM_NAME="langflow-dev" +IMAGE_FAMILY="debian-11" +IMAGE_PROJECT="debian-cloud" +BOOT_DISK_SIZE="100GB" +ZONE="us-central1-a" +REGION="us-central1" +VPC_NAME="default" +SUBNET_NAME="default" +SUBNET_RANGE="10.128.0.0/20" +NAT_GATEWAY_NAME="nat-gateway" +CLOUD_ROUTER_NAME="nat-client" + +# Set the GCP project's compute region +gcloud config set compute/region $REGION + +# Check if the VPC exists, and create it if not +vpc_exists=$(gcloud compute networks list --filter="name=$VPC_NAME" --format="value(name)") +if [[ -z "$vpc_exists" ]]; then + gcloud compute networks create $VPC_NAME --subnet-mode=custom +fi + +# Check if the subnet exists, and create it if not +subnet_exists=$(gcloud compute networks subnets list --filter="name=$SUBNET_NAME AND region=$REGION" --format="value(name)") +if [[ -z "$subnet_exists" ]]; then + gcloud compute networks subnets create $SUBNET_NAME --network=$VPC_NAME --region=$REGION --range=$SUBNET_RANGE +fi + +# Create a firewall rule to allow TCP port 8080 for all instances in the VPC +firewall_8080_exists=$(gcloud compute firewall-rules list --filter="name=allow-tcp-8080" --format="value(name)") +if [[ -z "$firewall_8080_exists" ]]; then + gcloud compute firewall-rules create allow-tcp-8080 --network $VPC_NAME --allow tcp:8080 --source-ranges 0.0.0.0/0 --direction INGRESS +fi + +# Create a firewall rule to allow IAP traffic +firewall_iap_exists=$(gcloud compute firewall-rules list --filter="name=allow-iap" --format="value(name)") +if [[ -z "$firewall_iap_exists" ]]; then + gcloud compute firewall-rules create allow-iap --network $VPC_NAME --allow tcp:80,tcp:443 --source-ranges 35.235.240.0/20 --direction INGRESS +fi + +# Create the Cloud Router and NAT Gateway +cloud_router_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(name)") +if [[ -z "$cloud_router_exists" ]]; then + gcloud compute routers create $CLOUD_ROUTER_NAME --network $VPC_NAME --region $REGION +fi + +nat_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(nats.name)") +if [[ -z "$nat_exists" ]]; then + gcloud compute routers nats create $NAT_GATEWAY_NAME --router $CLOUD_ROUTER_NAME --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --enable-logging --region $REGION +fi + +# Define the startup script as a multiline Bash here-doc +STARTUP_SCRIPT=$(cat <<'EOF' +#!/bin/bash + +# Update and upgrade the system +apt -y update +apt -y upgrade + +# Install Python 3 pip, Langflow, and Nginx +apt -y install python3-pip +pip install langflow +apt-get -y install nginx + +# Configure Nginx for Langflow +touch /etc/nginx/sites-available/langflow-app +echo "server { + listen 0.0.0.0:8080; + + location / { + proxy_pass http://127.0.0.1:7860; + proxy_set_header Host "\$host"; + proxy_set_header X-Real-IP "\$remote_addr"; + proxy_set_header X-Forwarded-For "\$proxy_add_x_forwarded_for"; + } +}" >> /etc/nginx/sites-available/langflow-app +ln -s /etc/nginx/sites-available/langflow-app /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl restart nginx +langflow +EOF +) + +# Create a temporary file to store the startup script +tempfile=$(mktemp) +echo "$STARTUP_SCRIPT" > $tempfile + +# Create the VM instance with the specified configuration and startup script +gcloud compute instances create $VM_NAME \ + --image-family $IMAGE_FAMILY \ + --image-project $IMAGE_PROJECT \ + --boot-disk-size $BOOT_DISK_SIZE \ + --machine-type=n1-standard-4 \ + --metadata-from-file startup-script=$tempfile \ + --zone $ZONE \ + --network $VPC_NAME \ + --subnet $SUBNET_NAME \ + -preemptible + +# Remove the temporary file after the VM is created +rm $tempfile diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index b53d3c6d2..0d619090f 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -39,7 +39,8 @@ The script will: 3. Create a Compute Engine VM instance with the specified configuration and startup script 4. Configure Nginx to serve Langflow on TCP port 8080 -> The process may take approximately 30 minutes to complete. Rest assured that progress is being made, and you'll be able to proceed once the process is finished. + +> The process may take approximately 30 minutes to complete. Rest assured that progress is being made, and you'll be able to proceed once the process is finished. In the next step, you'll learn how to connect to the Langflow VM. @@ -75,7 +76,9 @@ gcloud compute routers delete nat-client --region us-central1 --quiet The following network settings and services are used during this walkthrough. If you plan to continue using the project after the walkthrough, you may keep these configurations in place. However, if you decide to remove them after completing the walkthrough, you can use the following gcloud commands: -> These commands will delete the firewall rules and network configurations created during the walkthrough. Make sure to run them only if you no longer need these settings. + + +> These commands will delete the firewall rules and network configurations created during the walkthrough. Make sure to run them only if you no longer need these settings. ``` gcloud compute firewall-rules delete allow-tcp-8080 --quiet diff --git a/scripts/walkthroughtutorial_spot.md b/scripts/walkthroughtutorial_spot.md new file mode 100644 index 000000000..168a67046 --- /dev/null +++ b/scripts/walkthroughtutorial_spot.md @@ -0,0 +1,88 @@ +# Deploy Langflow on Google Cloud Platform + +**Duration**: 45 minutes +**Author**: [Robert Wilkins III](https://www.linkedin.com/in/robertwilkinsiii) + +## Introduction + +In this tutorial, you will learn how to deploy Langflow on [Google Cloud Platform](https://cloud.google.com/) (GCP) using Google Cloud Shell. + +This tutorial assumes you have a GCP account and basic knowledge of Google Cloud Shell. If you're not familiar with Cloud Shell, you can review the [Cloud Shell documentation](https://cloud.google.com/shell/docs). + +## Set up your environment + +Before you start, make sure you have the following prerequisites: + +- A GCP account with the necessary permissions to create resources +- A project on GCP where you want to deploy Langflow + +[**Select your GCP project**] + + + +In the next step, you'll configure the GCP environment and deploy Langflow. + +## Configure the GCP environment and deploy Langflow +Run the deploy_langflow_gcp_spot.sh script to configure the GCP environment and deploy Langflow: + +```sh +gcloud config set project +bash ./deploy_langflow_gcp.sh +``` + +The script will: + +1. Check if the required resources (VPC, subnet, firewall rules, and Cloud Router) exist and create them if needed +2. Create a startup script to install Python, Langflow, and Nginx +3. Create a Compute Engine VM instance with the specified configuration and startup script +4. Configure Nginx to serve Langflow on TCP port 8080 + +> The process may take approximately 30 minutes to complete. Rest assured that progress is being made, and you'll be able to proceed once the process is finished. + +In the next step, you'll learn how to connect to the Langflow VM. + +## Connect to the Langflow VM +To connect to your new Langflow VM, follow these steps: + +1. Navigate to the [VM instances](https://console.cloud.google.com/compute/instances) page and click on the external IP for your VM. Make sure to use HTTP and set the port to 8080 +
**or** +3. Run the following command to display the URL for your Langflow environment: +```bash +export LANGFLOW_IP=$(gcloud compute instances list --filter="NAME=langflow-dev" --format="value(EXTERNAL_IP)") + +echo http://$LANGFLOW_IP:8080 +``` + +4. Click on the Langflow URL in cloudshell to be greeted by the Langflow Dev environment + +Congratulations! You have successfully deployed Langflow on Google Cloud Platform. + + + +## Cleanup +If you want to remove the resources created during this tutorial, you can use the following commands: + +```sql +gcloud compute instances delete langflow-dev --zone us-central1-a --quiet + +gcloud compute routers nats delete nat-gateway --router nat-client --region us-central1 --quiet + +gcloud compute routers delete nat-client --region us-central1 --quiet + +``` +The following network settings and services are used during this walkthrough. If you plan to continue using the project after the walkthrough, you may keep these configurations in place. + +However, if you decide to remove them after completing the walkthrough, you can use the following gcloud commands: +> These commands will delete the firewall rules and network configurations created during the walkthrough. Make sure to run them only if you no longer need these settings. + +``` +gcloud compute firewall-rules delete allow-tcp-8080 --quiet + +gcloud compute firewall-rules delete allow-iap --quiet + +gcloud compute networks subnets delete default --region us-central1 --quiet + +gcloud compute networks delete default --quiet +``` From adc93c7902e54ae699e25862f066155399a2bd3c Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 05:10:38 +0000 Subject: [PATCH 49/73] improve grammer and remove nat --- README.md | 7 ++++--- scripts/deploy_langflow_gcp.sh | 11 ----------- scripts/deploy_langflow_gcp_spot.sh | 11 ----------- scripts/walkthroughtutorial.md | 5 ----- 4 files changed, 4 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index eaaf84331..3be5d99a9 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,12 @@ Next, run: ### Deploy Langflow on Google Cloud Platform -Follow our step-by-step guide to deploy Langflow on Google Cloud Platform (GCP) using Google Cloud Shell. The guide is available in the [Langflow in Google Cloud Platform](GCP_DEPLOYMENT.md) document. +Follow our step-by-step guide to deploy Langflow on Google Cloud Platform (GCP) using Google Cloud Shell. The guide is available in the [**Langflow in Google Cloud Platform**](GCP_DEPLOYMENT.md) document. -Alternatively, click the "Open in Cloud Shell" button below to launch Google Cloud Shell, clone the Langflow repository, and start an interactive tutorial that will guide you through the process of setting up the necessary resources and deploying Langflow on your GCP project. +Alternatively, click the **"Open in Cloud Shell"** button below to launch Google Cloud Shell, clone the Langflow repository, and start an **interactive tutorial** that will guide you through the process of setting up the necessary resources and deploying Langflow on your GCP project. + +[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=walkthroughtutorial_spot.md) -[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/genome21/langflow&working_dir=scripts&shellonly=true&tutorial=GCP_SETUP_TUTORIAL.md) ## 🎨 Creating Flows diff --git a/scripts/deploy_langflow_gcp.sh b/scripts/deploy_langflow_gcp.sh index 3e20e9589..2c3dc0420 100644 --- a/scripts/deploy_langflow_gcp.sh +++ b/scripts/deploy_langflow_gcp.sh @@ -38,17 +38,6 @@ if [[ -z "$firewall_iap_exists" ]]; then gcloud compute firewall-rules create allow-iap --network $VPC_NAME --allow tcp:80,tcp:443 --source-ranges 35.235.240.0/20 --direction INGRESS fi -# Create the Cloud Router and NAT Gateway -cloud_router_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(name)") -if [[ -z "$cloud_router_exists" ]]; then - gcloud compute routers create $CLOUD_ROUTER_NAME --network $VPC_NAME --region $REGION -fi - -nat_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(nats.name)") -if [[ -z "$nat_exists" ]]; then - gcloud compute routers nats create $NAT_GATEWAY_NAME --router $CLOUD_ROUTER_NAME --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --enable-logging --region $REGION -fi - # Define the startup script as a multiline Bash here-doc STARTUP_SCRIPT=$(cat <<'EOF' #!/bin/bash diff --git a/scripts/deploy_langflow_gcp_spot.sh b/scripts/deploy_langflow_gcp_spot.sh index 7ddc93b96..065b6013f 100644 --- a/scripts/deploy_langflow_gcp_spot.sh +++ b/scripts/deploy_langflow_gcp_spot.sh @@ -38,17 +38,6 @@ if [[ -z "$firewall_iap_exists" ]]; then gcloud compute firewall-rules create allow-iap --network $VPC_NAME --allow tcp:80,tcp:443 --source-ranges 35.235.240.0/20 --direction INGRESS fi -# Create the Cloud Router and NAT Gateway -cloud_router_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(name)") -if [[ -z "$cloud_router_exists" ]]; then - gcloud compute routers create $CLOUD_ROUTER_NAME --network $VPC_NAME --region $REGION -fi - -nat_exists=$(gcloud compute routers list --filter="name=$CLOUD_ROUTER_NAME" --format="value(nats.name)") -if [[ -z "$nat_exists" ]]; then - gcloud compute routers nats create $NAT_GATEWAY_NAME --router $CLOUD_ROUTER_NAME --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --enable-logging --region $REGION -fi - # Define the startup script as a multiline Bash here-doc STARTUP_SCRIPT=$(cat <<'EOF' #!/bin/bash diff --git a/scripts/walkthroughtutorial.md b/scripts/walkthroughtutorial.md index 0d619090f..fa6e3c11d 100644 --- a/scripts/walkthroughtutorial.md +++ b/scripts/walkthroughtutorial.md @@ -67,11 +67,6 @@ If you want to remove the resources created during this tutorial, you can use th ```sql gcloud compute instances delete langflow-dev --zone us-central1-a --quiet - -gcloud compute routers nats delete nat-gateway --router nat-client --region us-central1 --quiet - -gcloud compute routers delete nat-client --region us-central1 --quiet - ``` The following network settings and services are used during this walkthrough. If you plan to continue using the project after the walkthrough, you may keep these configurations in place. From e90b036b011e27b32b100d2d0ac7787424ea3d4d Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 05:11:28 +0000 Subject: [PATCH 50/73] remove the nats --- scripts/walkthroughtutorial_spot.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scripts/walkthroughtutorial_spot.md b/scripts/walkthroughtutorial_spot.md index 168a67046..751f03d78 100644 --- a/scripts/walkthroughtutorial_spot.md +++ b/scripts/walkthroughtutorial_spot.md @@ -66,11 +66,6 @@ If you want to remove the resources created during this tutorial, you can use th ```sql gcloud compute instances delete langflow-dev --zone us-central1-a --quiet - -gcloud compute routers nats delete nat-gateway --router nat-client --region us-central1 --quiet - -gcloud compute routers delete nat-client --region us-central1 --quiet - ``` The following network settings and services are used during this walkthrough. If you plan to continue using the project after the walkthrough, you may keep these configurations in place. From b9a9892db633e844a7142031592b43f8a98e721f Mon Sep 17 00:00:00 2001 From: Robert Wilkins III <1147229+genome21@users.noreply.github.com> Date: Thu, 20 Apr 2023 05:14:37 +0000 Subject: [PATCH 51/73] layout changes --- GCP_DEPLOYMENT.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/GCP_DEPLOYMENT.md b/GCP_DEPLOYMENT.md index 0491dabb0..edb7e043c 100644 --- a/GCP_DEPLOYMENT.md +++ b/GCP_DEPLOYMENT.md @@ -17,7 +17,8 @@ This script sets up a Debian-based VM with the Langflow package, Nginx, and the When running as a [spot (preemptible) instance](https://cloud.google.com/compute/docs/instances/preemptible), the code and VM will behave the same way as in a regular instance, executing the startup script to configure the environment, install necessary dependencies, and run the Langflow application. However, **due to the nature of spot instances, the VM may be terminated at any time if Google Cloud needs to reclaim the resources**. This makes spot instances suitable for fault-tolerant, stateless, or interruptible workloads that can handle unexpected terminations and restarts. -## Pricing +## Pricing (approximate) +> For a more accurate breakdown of costs, please use the [**GCP Pricing Calculator**](https://cloud.google.com/products/calculator)
| Component | Regular Cost (Hourly) | Regular Cost (Monthly) | Spot/Preemptible Cost (Hourly) | Spot/Preemptible Cost (Monthly) | Notes | @@ -25,6 +26,3 @@ When running as a [spot (preemptible) instance](https://cloud.google.com/compute | 100 GB Disk | - | $10/month | - | $10/month | Disk cost remains the same for both regular and Spot/Preemptible VMs | | VM (n1-standard-4) | $0.15/hr | ~$108/month | ~$0.04/hr | ~$29/month | The VM cost can be significantly reduced using a Spot/Preemptible instance | | **Total** | **$0.15/hr** | **~$118/month** | **~$0.04/hr** | **~$39/month** | Total costs for running the VM and disk 24/7 for an entire month | - -> For a more accurate breakdown of costs, please use the [**GCP Pricing Calculator**](https://cloud.google.com/products/calculator) - From b1971570c906d377e797a56749efb16c2feddb6d Mon Sep 17 00:00:00 2001 From: Paul Lockett Date: Thu, 30 Mar 2023 14:20:20 -0700 Subject: [PATCH 52/73] Correct run instructions Fix this for future users so they can get it up and running without having to probe the GitHub forum --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3be5d99a9..3cc0372aa 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ You can install LangFlow from pip: Next, run: -`langflow` +`python -m langflow` ### Deploy Langflow on Google Cloud Platform From ad24cdc1dd6aa00211c405f48d5099df6def2d70 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Sun, 23 Apr 2023 14:25:55 -0300 Subject: [PATCH 53/73] Update README.md --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3cc0372aa..3ae891751 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,19 @@ LangFlow is a GUI for [LangChain](https://github.com/hwchase17/langchain), desig ### Locally You can install LangFlow from pip: -`pip install langflow` +```shell +pip install langflow +``` Next, run: -`python -m langflow` +```shell +python -m langflow +``` +or +```shell +langflow +``` ### Deploy Langflow on Google Cloud Platform From 76162a9ffa8314013fadb04217e09a688a635e97 Mon Sep 17 00:00:00 2001 From: Rodrigo Nader Date: Sun, 23 Apr 2023 23:06:10 -0300 Subject: [PATCH 54/73] feat(langflow): Handle ChromaDB NotEnoughElementsException This change adds error handling to catch a specific exception that may occur when processing documents with the ChromaDB library. If there are not enough documents for indexing, the error message will suggest reducing the chunk size in TextSplitter. --- src/backend/langflow/interface/run.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/backend/langflow/interface/run.py b/src/backend/langflow/interface/run.py index 300e09e01..deba28586 100644 --- a/src/backend/langflow/interface/run.py +++ b/src/backend/langflow/interface/run.py @@ -1,6 +1,7 @@ import contextlib import io from typing import Any, Dict +from chromadb.errors import NotEnoughElementsException from langflow.cache.utils import compute_dict_hash, load_cache, memoize_dict from langflow.graph.graph import Graph @@ -230,6 +231,10 @@ def get_result_and_thought_using_graph(langchain_object, message: str): else: thought = output_buffer.getvalue() + except NotEnoughElementsException as exc: + raise ValueError( + "Error: Not enough documents for ChromaDB to index. Try reducing chunk size in TextSplitter." + ) from exc except Exception as exc: raise ValueError(f"Error: {str(exc)}") from exc return result, thought From 23fbec9d42e775f4f9abc268ccea5a700cac7c50 Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Mon, 24 Apr 2023 08:40:06 -0300 Subject: [PATCH 55/73] feat(loading.py): add error handling for empty documents in vectorstore instantiation feat(loading.py): add optional build parameter to load_flow_from_json function --- src/backend/langflow/interface/loading.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/interface/loading.py b/src/backend/langflow/interface/loading.py index 11db47ee6..1b404f38c 100644 --- a/src/backend/langflow/interface/loading.py +++ b/src/backend/langflow/interface/loading.py @@ -68,6 +68,13 @@ def instantiate_class(node_type: str, base_type: str, params: Dict) -> Any: params.pop("model") return class_object(**params) elif base_type == "vectorstores": + if len(params.get("documents", [])) == 0: + # Error when the pdf or other source was not correctly + # loaded. + raise ValueError( + "The source you provided did not load correctly or was empty." + "This may cause an error in the vectorstore." + ) return class_object.from_documents(**params) elif base_type == "documentloaders": return class_object(**params).load() @@ -79,7 +86,7 @@ def instantiate_class(node_type: str, base_type: str, params: Dict) -> Any: return class_object(**params) -def load_flow_from_json(path: str): +def load_flow_from_json(path: str, build=True): # This is done to avoid circular imports from langflow.graph import Graph @@ -96,7 +103,7 @@ def load_flow_from_json(path: str): # Nodes, edges and root node edges = data_graph["edges"] graph = Graph(nodes, edges) - return graph.build() + return graph.build() if build else graph def replace_zero_shot_prompt_with_prompt_template(nodes): From a15d605cc82f56e27e876f426210f873c84b892c Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 24 Apr 2023 19:03:20 -0300 Subject: [PATCH 56/73] 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 58/73] 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 59/73] 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 60/73] 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 61/73] 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 62/73] 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 63/73] 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 64/73] 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 65/73] 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 66/73] 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 4fd659703fa9cb9107cebb81505d154a902a358d Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 16:35:44 -0300 Subject: [PATCH 67/73] 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 68/73] 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 69/73] 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 b526c436cd6d4a2f65e0249044de8176d117170e Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Tue, 25 Apr 2023 17:34:14 -0300 Subject: [PATCH 70/73] 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 71/73] 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 72/73] 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 ( + <> +