From b3201ce8d77d783917ae7e2535ca5069a87bce81 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 14:32:03 -0300 Subject: [PATCH 1/4] add error handling for missing vertices --- src/backend/langflow/graph/graph/base.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index 3c772c897..2c1d7eaf3 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -7,12 +7,8 @@ from langflow.graph.graph.constants import lazy_load_vertex_dict from langflow.graph.graph.utils import process_flow from langflow.graph.schema import InterfaceComponentTypes from langflow.graph.vertex.base import Vertex -from langflow.graph.vertex.types import ( - ChatVertex, - FileToolVertex, - LLMVertex, - ToolkitVertex, -) +from langflow.graph.vertex.types import (ChatVertex, FileToolVertex, LLMVertex, + ToolkitVertex) from langflow.interface.tools.constants import FILE_TOOLS from langflow.utils import payload from loguru import logger @@ -216,7 +212,10 @@ class Graph: def get_vertex(self, vertex_id: str) -> Union[None, Vertex]: """Returns a vertex by id.""" - return self.vertex_map.get(vertex_id) + try: + return self.vertex_map.get(vertex_id) + except KeyError: + raise ValueError(f"Vertex {vertex_id} not found") def get_vertex_edges(self, vertex_id: str) -> List[ContractEdge]: """Returns a list of edges for a given vertex.""" From 3bb3ca7f3a17fd38ea19678d7ad67c04353b8813 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 14:32:13 -0300 Subject: [PATCH 2/4] Add support for dumping artifacts as YAML string --- src/backend/langflow/graph/vertex/types.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/graph/vertex/types.py b/src/backend/langflow/graph/vertex/types.py index 8d23059ce..cb4684d08 100644 --- a/src/backend/langflow/graph/vertex/types.py +++ b/src/backend/langflow/graph/vertex/types.py @@ -2,6 +2,7 @@ import ast import json from typing import Callable, Dict, List, Optional, Union +import yaml from langchain_core.messages import AIMessage from langflow.graph.utils import UnbuiltObject, flatten_list from langflow.graph.vertex.base import StatefulVertex, StatelessVertex @@ -343,8 +344,11 @@ class ChatVertex(StatelessVertex): return str(task.info) else: return f"Task {self.task_id} is not running" - if self.artifacts and "repr" in self.artifacts: - return self.artifacts["repr"] or super()._built_object_repr() + if self.artifacts: + # dump as a yaml string + yaml_str = yaml.dump(self.artifacts, default_flow_style=False) + return yaml_str + return super()._built_object_repr() async def _run(self, *args, **kwargs): if self.is_interface_component: From 67f826b43f2d0fe31cb3a0154168e18b71aa50ff Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 20 Feb 2024 14:32:34 -0300 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=94=A7=20chore(chat.py):=20remove=20u?= =?UTF-8?q?nused=20imports=20and=20variables=20to=20improve=20code=20reada?= =?UTF-8?q?bility=20and=20maintainability=20=F0=9F=90=9B=20fix(chat.py):?= =?UTF-8?q?=20fix=20error=20handling=20in=20build=5Fvertex=20function=20to?= =?UTF-8?q?=20correctly=20handle=20exceptions=20and=20improve=20error=20re?= =?UTF-8?q?porting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/chat.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index d49f4dc4a..d226df9bd 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -3,7 +3,6 @@ from typing import Optional from fastapi import ( APIRouter, - Body, Depends, HTTPException, WebSocket, @@ -26,7 +25,6 @@ from langflow.api.v1.schemas import ( VerticesOrderResponse, ) from langflow.graph.graph.base import Graph -from langflow.processing.process import process_tweaks_on_graph from langflow.services.auth.utils import ( get_current_active_user, get_current_user_for_websocket, @@ -318,11 +316,10 @@ async def build_vertex( vertex_id: str, chat_service: "ChatService" = Depends(get_chat_service), current_user=Depends(get_current_active_user), - tweaks: dict = Body(None), - inputs: dict = Body(None), ): """Build a vertex instead of the entire graph.""" try: + start_time = time.perf_counter() cache = chat_service.get_cache(flow_id) if not cache: # If there's no cache @@ -336,11 +333,8 @@ async def build_vertex( graph = cache.get("result") result_dict = {} duration = "" - start_time = time.perf_counter() - if tweaks: - graph = process_tweaks_on_graph(graph, tweaks) - if not (vertex := graph.get_vertex(vertex_id)): - raise ValueError(f"Invalid vertex {vertex_id}") + + vertex = graph.get_vertex(vertex_id) try: if not vertex.pinned or not vertex._built: await vertex.build(user_id=current_user.id) @@ -368,7 +362,7 @@ async def build_vertex( raise ValueError(f"No result found for vertex {vertex_id}") chat_service.set_cache(flow_id, graph) except Exception as exc: - params = str(exc) + params = repr(exc) valid = False result_dict = ResultDict(results={}) artifacts = {} From ad6f362d8be0b5b6e239300fc0868f287da681d8 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Tue, 20 Feb 2024 22:52:03 +0100 Subject: [PATCH 4/4] Added "Saved" tooltip at header --- .../components/menuBar/index.tsx | 24 +++++++++++++++++++ src/frontend/src/constants/constants.ts | 2 +- src/frontend/src/stores/flowsManagerStore.ts | 5 +++- src/frontend/src/stores/storeStore.tsx | 18 -------------- src/frontend/src/types/flow/index.ts | 2 ++ .../src/types/zustand/flowsManager/index.ts | 1 + 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index cca170067..73331fb27 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -13,6 +13,8 @@ import FlowSettingsModal from "../../../../modals/flowSettingsModal"; import useAlertStore from "../../../../stores/alertStore"; import useFlowStore from "../../../../stores/flowStore"; import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; +import { cn } from "../../../../utils/utils"; +import Tooltip from "../../../TooltipComponent"; import IconComponent from "../../../genericIconComponent"; import { Button } from "../../../ui/button"; @@ -26,6 +28,7 @@ export const MenuBar = ({ const setErrorData = useAlertStore((state) => state.setErrorData); const undo = useFlowsManagerStore((state) => state.undo); const redo = useFlowsManagerStore((state) => state.redo); + const saveLoading = useFlowsManagerStore((state) => state.saveLoading); const [openSettings, setOpenSettings] = useState(false); const n = useFlowStore((state) => state.nodes); @@ -112,6 +115,27 @@ export const MenuBar = ({ setOpen={setOpenSettings} > + +
+ + {saveLoading ? "Saving..." : "Saved"} +
+
) : ( <> diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index b9422efab..eeac6d060 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -681,4 +681,4 @@ export const LANGFLOW_SUPPORTED_TYPES = new Set([ export const priorityFields = new Set(["code", "template"]); export const INPUT_TYPES = new Set(["ChatInput", "TextInput"]); -export const OUTPUT_TYPES = new Set(["ChatOutput"]); +export const OUTPUT_TYPES = new Set(["ChatOutput",]); diff --git a/src/frontend/src/stores/flowsManagerStore.ts b/src/frontend/src/stores/flowsManagerStore.ts index 4a64b3125..3b4640b21 100644 --- a/src/frontend/src/stores/flowsManagerStore.ts +++ b/src/frontend/src/stores/flowsManagerStore.ts @@ -52,6 +52,7 @@ const useFlowsManagerStore = create((set, get) => ({ }); }, currentFlow: undefined, + saveLoading: false, isLoading: true, setIsLoading: (isLoading: boolean) => set({ isLoading }), refreshFlows: () => { @@ -82,7 +83,7 @@ const useFlowsManagerStore = create((set, get) => ({ if (saveTimeoutId) { clearTimeout(saveTimeoutId); } - + set({ saveLoading: true }); // Set up a new timeout. saveTimeoutId = setTimeout(() => { if (get().currentFlow) { @@ -94,6 +95,7 @@ const useFlowsManagerStore = create((set, get) => ({ }, 300); // Delay of 300ms. }, saveFlow: (flow: FlowType, silent?: boolean) => { + set({ saveLoading: true }) return new Promise((resolve, reject) => { updateFlowInDatabase(flow) .then((updatedFlow) => { @@ -115,6 +117,7 @@ const useFlowsManagerStore = create((set, get) => ({ //update tabs state resolve(); + set({ saveLoading: false }) } }) .catch((err) => { diff --git a/src/frontend/src/stores/storeStore.tsx b/src/frontend/src/stores/storeStore.tsx index 43d16c177..2d519e21a 100644 --- a/src/frontend/src/stores/storeStore.tsx +++ b/src/frontend/src/stores/storeStore.tsx @@ -17,21 +17,3 @@ export const useStoreStore = create((set) => ({ checkHasStore().then((res) => { useStoreStore.setState({ hasStore: res?.enabled ?? false }); }); - -const fetchApiData = async () => { - useStoreStore.setState({ loadingApiKey: true }); - try { - const res = await checkHasApiKey(); - - useStoreStore.setState({ - loadingApiKey: false, - validApiKey: res?.is_valid ?? false, - hasApiKey: res?.has_api_key ?? false, - }); - } catch (e) { - useStoreStore.setState({ loadingApiKey: false }); - console.log(e); - } -}; - -fetchApiData(); diff --git a/src/frontend/src/types/flow/index.ts b/src/frontend/src/types/flow/index.ts index 5f2ed1dc4..127e1a704 100644 --- a/src/frontend/src/types/flow/index.ts +++ b/src/frontend/src/types/flow/index.ts @@ -10,6 +10,8 @@ export type FlowType = { style?: FlowStyleType; is_component?: boolean; last_tested_version?: string; + updated_at?: string; + date_created?: string; parent?: string; }; diff --git a/src/frontend/src/types/zustand/flowsManager/index.ts b/src/frontend/src/types/zustand/flowsManager/index.ts index 2a20c20d8..471d4cf17 100644 --- a/src/frontend/src/types/zustand/flowsManager/index.ts +++ b/src/frontend/src/types/zustand/flowsManager/index.ts @@ -7,6 +7,7 @@ export type FlowsManagerStoreType = { currentFlow: FlowType | undefined; currentFlowId: string; setCurrentFlowId: (currentFlowId: string) => void; + saveLoading: boolean; isLoading: boolean; setIsLoading: (isLoading: boolean) => void; refreshFlows: () => Promise;