From 39434eadc413d6dc7dde0305665326cc059c335d Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Fri, 8 Mar 2024 11:36:32 -0300 Subject: [PATCH] Formatting --- src/backend/langflow/api/utils.py | 32 +-- src/backend/langflow/api/v1/base.py | 20 +- src/backend/langflow/api/v1/chat.py | 4 +- src/backend/langflow/api/v1/endpoints.py | 41 +--- src/backend/langflow/api/v1/validate.py | 8 +- src/backend/langflow/base/io/chat.py | 4 +- src/backend/langflow/base/prompts/utils.py | 8 +- .../langflow/components/data/APIRequest.py | 9 +- .../experimental/ClearMessageHistory.py | 2 +- .../components/experimental/RunFlow.py | 12 +- .../components/experimental/TextToRecord.py | 7 +- .../components/helpers/PythonFunction.py | 1 + .../langflow/components/inputs/Prompt.py | 4 +- .../langflow/components/outputs/ChatOutput.py | 1 + .../RecursiveCharacterTextSplitter.py | 4 +- .../components/vectorstores/Chroma.py | 7 +- .../vectorstores/MongoDBAtlasVector.py | 8 +- .../langflow/components/vectorstores/Redis.py | 4 +- .../vectorstores/SupabaseVectorStore.py | 4 +- .../components/vectorstores/Vectara.py | 4 +- .../components/vectorstores/Weaviate.py | 4 +- .../components/vectorstores/pgvector.py | 4 +- src/backend/langflow/graph/edge/base.py | 43 +--- src/backend/langflow/graph/graph/base.py | 108 +++------ src/backend/langflow/graph/graph/constants.py | 5 +- src/backend/langflow/graph/vertex/base.py | 110 ++------- src/backend/langflow/graph/vertex/types.py | 47 +--- src/backend/langflow/initial_setup/setup.py | 13 +- .../custom/code_parser/code_parser.py | 38 +--- .../custom_component/custom_component.py | 44 +--- .../langflow/interface/custom/utils.py | 70 ++---- .../langflow/interface/initialize/loading.py | 58 ++--- src/backend/langflow/interface/types.py | 8 +- src/backend/langflow/processing/load.py | 8 +- src/backend/langflow/processing/process.py | 32 +-- src/backend/langflow/schema/schema.py | 4 +- .../services/database/models/flow/model.py | 4 +- .../langflow/services/monitor/schema.py | 12 +- .../langflow/services/monitor/service.py | 4 +- src/backend/langflow/services/task/service.py | 4 +- src/backend/langflow/template/field/base.py | 10 +- src/backend/langflow/utils/util.py | 60 ++--- .../src/CustomNodes/GenericNode/index.tsx | 208 +++++++++--------- src/frontend/src/components/IOview/index.tsx | 7 +- .../src/components/NewFLowCard2/index.tsx | 45 ++-- .../src/components/chatComponent/index.tsx | 139 ++++++------ .../components/menuBar/index.tsx | 29 ++- .../components/keypairListComponent/index.tsx | 2 +- .../src/components/undrawCards/index.tsx | 141 ++++++++---- src/frontend/src/constants/constants.ts | 12 +- .../components/PageComponent/index.tsx | 2 +- .../extraSidebarComponent/index.tsx | 6 +- .../components/nodeToolbarComponent/index.tsx | 135 ++++++------ src/frontend/src/pages/MainPage/index.tsx | 12 +- src/frontend/tailwind.config.js | 4 +- tests/test_api_key.py | 2 +- tests/test_initial_setup.py | 15 +- tests/test_process.py | 24 +- 58 files changed, 630 insertions(+), 1027 deletions(-) diff --git a/src/backend/langflow/api/utils.py b/src/backend/langflow/api/utils.py index 2a38676d5..f51e0fd5f 100644 --- a/src/backend/langflow/api/utils.py +++ b/src/backend/langflow/api/utils.py @@ -20,9 +20,7 @@ API_WORDS = ["api", "key", "token"] def has_api_terms(word: str): - return "api" in word and ( - "key" in word or ("token" in word and "tokens" not in word) - ) + return "api" in word and ("key" in word or ("token" in word and "tokens" not in word)) def remove_api_keys(flow: dict): @@ -32,11 +30,7 @@ def remove_api_keys(flow: dict): node_data = node.get("data").get("node") template = node_data.get("template") for value in template.values(): - if ( - isinstance(value, dict) - and has_api_terms(value["name"]) - and value.get("password") - ): + if isinstance(value, dict) and has_api_terms(value["name"]) and value.get("password"): value["value"] = None return flow @@ -57,9 +51,7 @@ def build_input_keys_response(langchain_object, artifacts): input_keys_response["input_keys"][key] = value # If the object has memory, that memory will have a memory_variables attribute # memory variables should be removed from the input keys - if hasattr(langchain_object, "memory") and hasattr( - langchain_object.memory, "memory_variables" - ): + if hasattr(langchain_object, "memory") and hasattr(langchain_object.memory, "memory_variables"): # Remove memory variables from input keys input_keys_response["input_keys"] = { key: value @@ -69,9 +61,7 @@ def build_input_keys_response(langchain_object, artifacts): # Add memory variables to memory_keys input_keys_response["memory_keys"] = langchain_object.memory.memory_variables - if hasattr(langchain_object, "prompt") and hasattr( - langchain_object.prompt, "template" - ): + if hasattr(langchain_object, "prompt") and hasattr(langchain_object.prompt, "template"): input_keys_response["template"] = langchain_object.prompt.template return input_keys_response @@ -106,11 +96,7 @@ def raw_frontend_data_is_valid(raw_frontend_data): def is_valid_data(frontend_node, raw_frontend_data): """Check if the data is valid for processing.""" - return ( - frontend_node - and "template" in frontend_node - and raw_frontend_data_is_valid(raw_frontend_data) - ) + return frontend_node and "template" in frontend_node and raw_frontend_data_is_valid(raw_frontend_data) def update_template_values(frontend_template, raw_template): @@ -150,9 +136,7 @@ def get_file_path_value(file_path): # If the path is not in the cache dir, return empty string # This is to prevent access to files outside the cache dir # If the path is not a file, return empty string - if not path.exists() or not str(path).startswith( - user_cache_dir("langflow", "langflow") - ): + if not path.exists() or not str(path).startswith(user_cache_dir("langflow", "langflow")): return "" return file_path @@ -183,9 +167,7 @@ async def check_langflow_version(component: StoreComponentCreate): langflow_version = get_lf_version_from_pypi() if langflow_version is None: - raise HTTPException( - status_code=500, detail="Unable to verify the latest version of Langflow" - ) + raise HTTPException(status_code=500, detail="Unable to verify the latest version of Langflow") elif langflow_version != component.last_tested_version: warnings.warn( f"Your version of Langflow ({component.last_tested_version}) is outdated. " diff --git a/src/backend/langflow/api/v1/base.py b/src/backend/langflow/api/v1/base.py index eed84815f..b040d51c4 100644 --- a/src/backend/langflow/api/v1/base.py +++ b/src/backend/langflow/api/v1/base.py @@ -103,9 +103,7 @@ def fix_variable(var, invalid_chars, wrong_variables): # Handle variables starting with a number if var[0].isdigit(): invalid_chars.append(var[0]) - new_var, invalid_chars, wrong_variables = fix_variable( - var[1:], invalid_chars, wrong_variables - ) + new_var, invalid_chars, wrong_variables = fix_variable(var[1:], invalid_chars, wrong_variables) # Temporarily replace {{ and }} to avoid treating them as invalid new_var = new_var.replace("{{", "ᴛᴇᴍᴘᴏᴘᴇɴ").replace("}}", "ᴛᴇᴍᴘᴄʟᴏsᴇ") @@ -132,9 +130,7 @@ def check_variable(var, invalid_chars, wrong_variables, empty_variables): return wrong_variables, empty_variables -def check_for_errors( - input_variables, fixed_variables, wrong_variables, empty_variables -): +def check_for_errors(input_variables, fixed_variables, wrong_variables, empty_variables): if any(var for var in input_variables if var not in fixed_variables): error_message = ( f"Error: Input variables contain invalid characters or formats. \n" @@ -159,17 +155,11 @@ def check_input_variables(input_variables): if is_json_like(var): continue - new_var, wrong_variables, empty_variables = fix_variable( - var, invalid_chars, wrong_variables - ) - wrong_variables, empty_variables = check_variable( - var, INVALID_CHARACTERS, wrong_variables, empty_variables - ) + new_var, wrong_variables, empty_variables = fix_variable(var, invalid_chars, wrong_variables) + wrong_variables, empty_variables = check_variable(var, INVALID_CHARACTERS, wrong_variables, empty_variables) fixed_variables.append(new_var) variables_to_check.append(var) - check_for_errors( - variables_to_check, fixed_variables, wrong_variables, empty_variables - ) + check_for_errors(variables_to_check, fixed_variables, wrong_variables, empty_variables) return fixed_variables diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index c05e76325..77a99b035 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -122,9 +122,7 @@ async def build_vertex( else: raise ValueError(f"No result found for vertex {vertex_id}") next_vertices_ids = vertex.successors_ids - next_vertices_ids = [ - v for v in next_vertices_ids if graph.should_run_vertex(v) - ] + next_vertices_ids = [v for v in next_vertices_ids if graph.should_run_vertex(v)] result_data_response = ResultDataResponse(**result_dict.model_dump()) diff --git a/src/backend/langflow/api/v1/endpoints.py b/src/backend/langflow/api/v1/endpoints.py index 88870b49c..1d9950585 100644 --- a/src/backend/langflow/api/v1/endpoints.py +++ b/src/backend/langflow/api/v1/endpoints.py @@ -52,9 +52,7 @@ def get_all( raise HTTPException(status_code=500, detail=str(exc)) from exc -@router.post( - "/run/{flow_id}", response_model=RunResponse, response_model_exclude_none=True -) +@router.post("/run/{flow_id}", response_model=RunResponse, response_model_exclude_none=True) async def run_flow_with_caching( session: Annotated[Session, Depends(get_session)], flow_id: str, @@ -105,9 +103,7 @@ async def run_flow_with_caching( """ try: if inputs is not None: - input_values: list[dict[str, Union[str, list[str]]]] = [ - _input.model_dump() for _input in inputs - ] + input_values: list[dict[str, Union[str, list[str]]]] = [_input.model_dump() for _input in inputs] else: input_values = [{}] @@ -115,9 +111,7 @@ async def run_flow_with_caching( outputs = [] if session_id: - session_data = await session_service.load_session( - session_id, flow_id=flow_id - ) + session_data = await session_service.load_session(session_id, flow_id=flow_id) graph, artifacts = session_data if session_data else (None, None) task_result: Any = None if not graph: @@ -136,11 +130,7 @@ async def run_flow_with_caching( else: # Get the flow that matches the flow_id and belongs to the user # flow = session.query(Flow).filter(Flow.id == flow_id).filter(Flow.user_id == api_key_user.id).first() - flow = session.exec( - select(Flow) - .where(Flow.id == flow_id) - .where(Flow.user_id == api_key_user.id) - ).first() + flow = session.exec(select(Flow).where(Flow.id == flow_id).where(Flow.user_id == api_key_user.id)).first() if flow is None: raise ValueError(f"Flow {flow_id} not found") @@ -164,18 +154,12 @@ async def run_flow_with_caching( # StatementError('(builtins.ValueError) badly formed hexadecimal UUID string') if "badly formed hexadecimal UUID string" in str(exc): # This means the Flow ID is not a valid UUID which means it can't find the flow - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, detail=str(exc) - ) from exc + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc except ValueError as exc: if f"Flow {flow_id} not found" in str(exc): - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, detail=str(exc) - ) from exc + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc else: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc) - ) from exc + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc @router.post( @@ -204,8 +188,7 @@ async def process( """ # Raise a depreciation warning logger.warning( - "The /process endpoint is deprecated and will be removed in a future version. " - "Please use /run instead." + "The /process endpoint is deprecated and will be removed in a future version. " "Please use /run instead." ) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -277,16 +260,12 @@ async def custom_component( built_frontend_node = build_custom_component_template(component, user_id=user.id) - built_frontend_node = update_frontend_node_with_template_values( - built_frontend_node, raw_code.frontend_node - ) + built_frontend_node = update_frontend_node_with_template_values(built_frontend_node, raw_code.frontend_node) return built_frontend_node @router.post("/custom_component/reload", status_code=HTTPStatus.OK) -async def reload_custom_component( - path: str, user: User = Depends(get_current_active_user) -): +async def reload_custom_component(path: str, user: User = Depends(get_current_active_user)): from langflow.interface.custom.utils import build_custom_component_template try: diff --git a/src/backend/langflow/api/v1/validate.py b/src/backend/langflow/api/v1/validate.py index c2d294f64..09d32cb8e 100644 --- a/src/backend/langflow/api/v1/validate.py +++ b/src/backend/langflow/api/v1/validate.py @@ -46,9 +46,7 @@ def post_validate_prompt(prompt_request: ValidatePromptRequest): ) if not prompt_request.custom_fields: prompt_request.custom_fields = defaultdict(list) - old_custom_fields = get_old_custom_fields( - prompt_request.custom_fields, prompt_request.name - ) + old_custom_fields = get_old_custom_fields(prompt_request.custom_fields, prompt_request.name) add_new_variables_to_template( input_variables, @@ -65,9 +63,7 @@ def post_validate_prompt(prompt_request: ValidatePromptRequest): prompt_request.name, ) - update_input_variables_field( - input_variables, prompt_request.frontend_node.template - ) + update_input_variables_field(input_variables, prompt_request.frontend_node.template) return PromptValidationResponse( input_variables=input_variables, diff --git a/src/backend/langflow/base/io/chat.py b/src/backend/langflow/base/io/chat.py index b9c721190..2dafd7bc2 100644 --- a/src/backend/langflow/base/io/chat.py +++ b/src/backend/langflow/base/io/chat.py @@ -45,9 +45,7 @@ class ChatComponent(CustomComponent): return [] if not session_id or not sender or not sender_name: - raise ValueError( - "All of session_id, sender, and sender_name must be provided." - ) + raise ValueError("All of session_id, sender, and sender_name must be provided.") if isinstance(message, Record): record = message record.data.update( diff --git a/src/backend/langflow/base/prompts/utils.py b/src/backend/langflow/base/prompts/utils.py index c30d2d6a2..561d8256a 100644 --- a/src/backend/langflow/base/prompts/utils.py +++ b/src/backend/langflow/base/prompts/utils.py @@ -67,9 +67,7 @@ def validate_prompt(prompt_template: str, silent_errors: bool = False) -> list[s # Check if there are invalid characters in the input_variables input_variables = check_input_variables(input_variables) if any(var in INVALID_NAMES for var in input_variables): - raise ValueError( - f"Invalid input variables. None of the variables can be named {', '.join(input_variables)}. " - ) + raise ValueError(f"Invalid input variables. None of the variables can be named {', '.join(input_variables)}. ") try: PromptTemplate(template=prompt_template, input_variables=input_variables) @@ -118,9 +116,7 @@ def add_new_variables_to_template(input_variables, custom_fields, template, name raise HTTPException(status_code=500, detail=str(exc)) from exc -def remove_old_variables_from_template( - old_custom_fields, input_variables, custom_fields, template, name -): +def remove_old_variables_from_template(old_custom_fields, input_variables, custom_fields, template, name): for variable in old_custom_fields: if variable not in input_variables: try: diff --git a/src/backend/langflow/components/data/APIRequest.py b/src/backend/langflow/components/data/APIRequest.py index 12609e046..0873c2705 100644 --- a/src/backend/langflow/components/data/APIRequest.py +++ b/src/backend/langflow/components/data/APIRequest.py @@ -56,9 +56,7 @@ class APIRequest(CustomComponent): data = body if body else None payload = json.dumps(data) try: - response = await client.request( - method, url, headers=headers, content=payload, timeout=timeout - ) + response = await client.request(method, url, headers=headers, content=payload, timeout=timeout) try: result = response.json() except Exception: @@ -108,9 +106,6 @@ class APIRequest(CustomComponent): bodies = [body.data] async with httpx.AsyncClient() as client: results = await asyncio.gather( - *[ - self.make_request(client, method, u, headers, rec, timeout) - for u, rec in zip(urls, bodies) - ] + *[self.make_request(client, method, u, headers, rec, timeout) for u, rec in zip(urls, bodies)] ) return results diff --git a/src/backend/langflow/components/experimental/ClearMessageHistory.py b/src/backend/langflow/components/experimental/ClearMessageHistory.py index 6e29469ba..2ceab8f1a 100644 --- a/src/backend/langflow/components/experimental/ClearMessageHistory.py +++ b/src/backend/langflow/components/experimental/ClearMessageHistory.py @@ -5,7 +5,7 @@ from langflow.memory import delete_messages, get_messages class ClearMessageHistoryComponent(CustomComponent): display_name = "Clear Message History" description = "A component to clear the message history." - icon="ClearMessageHistory" + icon = "ClearMessageHistory" beta: bool = True def build_config(self): diff --git a/src/backend/langflow/components/experimental/RunFlow.py b/src/backend/langflow/components/experimental/RunFlow.py index 915296e9f..59ced9962 100644 --- a/src/backend/langflow/components/experimental/RunFlow.py +++ b/src/backend/langflow/components/experimental/RunFlow.py @@ -38,18 +38,12 @@ class RunFlowComponent(CustomComponent): return [] records = [] for message in messages: - message_dict = ( - message if isinstance(message, dict) else message.model_dump() - ) - record = Record( - text=message_dict.get("text", ""), data={"result": result_data} - ) + message_dict = message if isinstance(message, dict) else message.model_dump() + record = Record(text=message_dict.get("text", ""), data={"result": result_data}) records.append(record) return records - async def build( - self, input_value: Text, flow_name: str, tweaks: NestedDict - ) -> List[Record]: + async def build(self, input_value: Text, flow_name: str, tweaks: NestedDict) -> List[Record]: results: List[Optional[ResultData]] = await self.run_flow( input_value=input_value, flow_name=flow_name, tweaks=tweaks ) diff --git a/src/backend/langflow/components/experimental/TextToRecord.py b/src/backend/langflow/components/experimental/TextToRecord.py index 6a746598b..96ac4ad51 100644 --- a/src/backend/langflow/components/experimental/TextToRecord.py +++ b/src/backend/langflow/components/experimental/TextToRecord.py @@ -93,11 +93,6 @@ class TextToRecordComponent(CustomComponent): if mode == "Text": data = kwargs else: - data = { - k: v - for key, d in kwargs.items() - for k, v in d.items() - if key not in ["mode", "n_keys", "keys"] - } + data = {k: v for key, d in kwargs.items() for k, v in d.items() if key not in ["mode", "n_keys", "keys"]} record = Record(data=data) return record diff --git a/src/backend/langflow/components/helpers/PythonFunction.py b/src/backend/langflow/components/helpers/PythonFunction.py index a33c9dac1..0fab524cc 100644 --- a/src/backend/langflow/components/helpers/PythonFunction.py +++ b/src/backend/langflow/components/helpers/PythonFunction.py @@ -9,6 +9,7 @@ class PythonFunctionComponent(CustomComponent): display_name = "Python Function" description = "Define a Python function." icon = "Python" + def build_config(self): return { "function_code": { diff --git a/src/backend/langflow/components/inputs/Prompt.py b/src/backend/langflow/components/inputs/Prompt.py index 71ad12fcf..f56b48b4e 100644 --- a/src/backend/langflow/components/inputs/Prompt.py +++ b/src/backend/langflow/components/inputs/Prompt.py @@ -23,9 +23,7 @@ class PromptComponent(CustomComponent): ) -> Text: prompt_template = PromptTemplate.from_template(Text(template)) kwargs = dict_values_to_string(kwargs) - kwargs = { - k: "\n".join(v) if isinstance(v, list) else v for k, v in kwargs.items() - } + kwargs = {k: "\n".join(v) if isinstance(v, list) else v for k, v in kwargs.items()} try: formated_prompt = prompt_template.format(**kwargs) except Exception as exc: diff --git a/src/backend/langflow/components/outputs/ChatOutput.py b/src/backend/langflow/components/outputs/ChatOutput.py index 3fded100c..43f119c78 100644 --- a/src/backend/langflow/components/outputs/ChatOutput.py +++ b/src/backend/langflow/components/outputs/ChatOutput.py @@ -9,6 +9,7 @@ class ChatOutput(ChatComponent): display_name = "Chat Output" description = "Used to send a message to the chat." icon = "ChatOutput" + def build( self, sender: Optional[str] = "Machine", diff --git a/src/backend/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py b/src/backend/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py index 3a115d89a..acbef0f10 100644 --- a/src/backend/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py +++ b/src/backend/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py @@ -11,9 +11,7 @@ from langflow.utils.util import build_loader_repr_from_records, unescape_string class RecursiveCharacterTextSplitterComponent(CustomComponent): display_name: str = "Recursive Character Text Splitter" description: str = "Split text into chunks of a specified length." - documentation: str = ( - "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter" - ) + documentation: str = "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter" def build_config(self): return { diff --git a/src/backend/langflow/components/vectorstores/Chroma.py b/src/backend/langflow/components/vectorstores/Chroma.py index e00a0267a..0b8fbcb3a 100644 --- a/src/backend/langflow/components/vectorstores/Chroma.py +++ b/src/backend/langflow/components/vectorstores/Chroma.py @@ -84,8 +84,7 @@ class ChromaComponent(CustomComponent): if chroma_server_host is not None: chroma_settings = chromadb.config.Settings( - chroma_server_cors_allow_origins=chroma_server_cors_allow_origins - or None, + chroma_server_cors_allow_origins=chroma_server_cors_allow_origins or None, chroma_server_host=chroma_server_host, chroma_server_port=chroma_server_port or None, chroma_server_grpc_port=chroma_server_grpc_port or None, @@ -106,9 +105,7 @@ class ChromaComponent(CustomComponent): documents.append(_input) if documents is not None and embedding is not None: if len(documents) == 0: - raise ValueError( - "If documents are provided, there must be at least one document." - ) + raise ValueError("If documents are provided, there must be at least one document.") chroma = Chroma.from_documents( documents=documents, # type: ignore persist_directory=index_directory, diff --git a/src/backend/langflow/components/vectorstores/MongoDBAtlasVector.py b/src/backend/langflow/components/vectorstores/MongoDBAtlasVector.py index d94e3ad14..eee2cd8db 100644 --- a/src/backend/langflow/components/vectorstores/MongoDBAtlasVector.py +++ b/src/backend/langflow/components/vectorstores/MongoDBAtlasVector.py @@ -9,9 +9,7 @@ from langflow.schema.schema import Record class MongoDBAtlasComponent(CustomComponent): display_name = "MongoDB Atlas" - description = ( - "Construct a `MongoDB Atlas Vector Search` vector store from raw documents." - ) + description = "Construct a `MongoDB Atlas Vector Search` vector store from raw documents." icon = "MongoDB" def build_config(self): @@ -39,9 +37,7 @@ class MongoDBAtlasComponent(CustomComponent): try: from pymongo import MongoClient except ImportError: - raise ImportError( - "Please install pymongo to use MongoDB Atlas Vector Store" - ) + raise ImportError("Please install pymongo to use MongoDB Atlas Vector Store") try: mongo_client: MongoClient = MongoClient(mongodb_atlas_cluster_uri) collection = mongo_client[db_name][collection_name] diff --git a/src/backend/langflow/components/vectorstores/Redis.py b/src/backend/langflow/components/vectorstores/Redis.py index 5996ccc66..4dff685a7 100644 --- a/src/backend/langflow/components/vectorstores/Redis.py +++ b/src/backend/langflow/components/vectorstores/Redis.py @@ -66,9 +66,7 @@ class RedisComponent(CustomComponent): documents.append(_input) if not documents: if schema is None: - raise ValueError( - "If no documents are provided, a schema must be provided." - ) + raise ValueError("If no documents are provided, a schema must be provided.") redis_vs = Redis.from_existing_index( embedding=embedding, index_name=redis_index_name, diff --git a/src/backend/langflow/components/vectorstores/SupabaseVectorStore.py b/src/backend/langflow/components/vectorstores/SupabaseVectorStore.py index bc9d49e28..29b872895 100644 --- a/src/backend/langflow/components/vectorstores/SupabaseVectorStore.py +++ b/src/backend/langflow/components/vectorstores/SupabaseVectorStore.py @@ -35,9 +35,7 @@ class SupabaseComponent(CustomComponent): supabase_url: str = "", table_name: str = "", ) -> Union[VectorStore, SupabaseVectorStore, BaseRetriever]: - supabase: Client = create_client( - supabase_url, supabase_key=supabase_service_key - ) + supabase: Client = create_client(supabase_url, supabase_key=supabase_service_key) documents = [] for _input in inputs or []: if isinstance(_input, Record): diff --git a/src/backend/langflow/components/vectorstores/Vectara.py b/src/backend/langflow/components/vectorstores/Vectara.py index c427e139c..55171a6c1 100644 --- a/src/backend/langflow/components/vectorstores/Vectara.py +++ b/src/backend/langflow/components/vectorstores/Vectara.py @@ -15,9 +15,7 @@ from langflow.schema.schema import Record class VectaraComponent(CustomComponent): display_name: str = "Vectara" description: str = "Implementation of Vector Store using Vectara" - documentation = ( - "https://python.langchain.com/docs/integrations/vectorstores/vectara" - ) + documentation = "https://python.langchain.com/docs/integrations/vectorstores/vectara" icon = "Vectara" field_config = { "vectara_customer_id": { diff --git a/src/backend/langflow/components/vectorstores/Weaviate.py b/src/backend/langflow/components/vectorstores/Weaviate.py index 62f46c586..64037676c 100644 --- a/src/backend/langflow/components/vectorstores/Weaviate.py +++ b/src/backend/langflow/components/vectorstores/Weaviate.py @@ -12,9 +12,7 @@ from langflow.schema.schema import Record class WeaviateVectorStoreComponent(CustomComponent): display_name: str = "Weaviate" description: str = "Implementation of Vector Store using Weaviate" - documentation = ( - "https://python.langchain.com/docs/integrations/vectorstores/weaviate" - ) + documentation = "https://python.langchain.com/docs/integrations/vectorstores/weaviate" field_config = { "url": {"display_name": "Weaviate URL", "value": "http://localhost:8080"}, "api_key": { diff --git a/src/backend/langflow/components/vectorstores/pgvector.py b/src/backend/langflow/components/vectorstores/pgvector.py index ae3782714..1a3fb6f21 100644 --- a/src/backend/langflow/components/vectorstores/pgvector.py +++ b/src/backend/langflow/components/vectorstores/pgvector.py @@ -16,9 +16,7 @@ class PGVectorComponent(CustomComponent): display_name: str = "PGVector" description: str = "Implementation of Vector Store using PostgreSQL" - documentation = ( - "https://python.langchain.com/docs/integrations/vectorstores/pgvector" - ) + documentation = "https://python.langchain.com/docs/integrations/vectorstores/pgvector" def build_config(self): """ diff --git a/src/backend/langflow/graph/edge/base.py b/src/backend/langflow/graph/edge/base.py index 3b12146bf..0b4091ab5 100644 --- a/src/backend/langflow/graph/edge/base.py +++ b/src/backend/langflow/graph/edge/base.py @@ -13,9 +13,7 @@ if TYPE_CHECKING: class SourceHandle(BaseModel): - baseClasses: List[str] = Field( - ..., description="List of base classes for the source handle." - ) + baseClasses: List[str] = Field(..., description="List of base classes for the source handle.") dataType: str = Field(..., description="Data type for the source handle.") id: str = Field(..., description="Unique identifier for the source handle.") @@ -23,9 +21,7 @@ class SourceHandle(BaseModel): class TargetHandle(BaseModel): fieldName: str = Field(..., description="Field name for the target handle.") id: str = Field(..., description="Unique identifier for the target handle.") - inputTypes: Optional[List[str]] = Field( - None, description="List of input types for the target handle." - ) + inputTypes: Optional[List[str]] = Field(None, description="List of input types for the target handle.") type: str = Field(..., description="Type of the target handle.") @@ -54,24 +50,16 @@ class Edge: def validate_handles(self, source, target) -> None: if self.target_handle.inputTypes is None: - self.valid_handles = ( - self.target_handle.type in self.source_handle.baseClasses - ) + self.valid_handles = self.target_handle.type in self.source_handle.baseClasses else: self.valid_handles = ( - any( - baseClass in self.target_handle.inputTypes - for baseClass in self.source_handle.baseClasses - ) + any(baseClass in self.target_handle.inputTypes for baseClass in self.source_handle.baseClasses) or self.target_handle.type in self.source_handle.baseClasses ) if not self.valid_handles: logger.debug(self.source_handle) logger.debug(self.target_handle) - raise ValueError( - f"Edge between {source.vertex_type} and {target.vertex_type} " - f"has invalid handles" - ) + raise ValueError(f"Edge between {source.vertex_type} and {target.vertex_type} " f"has invalid handles") def __setstate__(self, state): self.source_id = state["source_id"] @@ -88,11 +76,7 @@ class Edge: # Both lists contain strings and sometimes a string contains the value we are # looking for e.g. comgin_out=["Chain"] and target_reqs=["LLMChain"] # so we need to check if any of the strings in source_types is in target_reqs - self.valid = any( - output in target_req - for output in self.source_types - for target_req in self.target_reqs - ) + self.valid = any(output in target_req for output in self.source_types for target_req in self.target_reqs) # Get what type of input the target node is expecting self.matched_type = next( @@ -103,10 +87,7 @@ class Edge: if no_matched_type: logger.debug(self.source_types) logger.debug(self.target_reqs) - raise ValueError( - f"Edge between {source.vertex_type} and {target.vertex_type} " - f"has no matched type" - ) + raise ValueError(f"Edge between {source.vertex_type} and {target.vertex_type} " f"has no matched type") def __repr__(self) -> str: return ( @@ -118,13 +99,9 @@ class Edge: return hash(self.__repr__()) def __eq__(self, __o: object) -> bool: - if not isinstance(__o, Edge): return False - return ( - self._source_handle == __o._source_handle - and self._target_handle == __o._target_handle - ) + return self._source_handle == __o._source_handle and self._target_handle == __o._target_handle class ContractEdge(Edge): @@ -181,9 +158,7 @@ class ContractEdge(Edge): return f"{self.source_id} -[{self.target_param}]-> {self.target_id}" -def log_transaction( - edge: ContractEdge, source: "Vertex", target: "Vertex", status, error=None -): +def log_transaction(edge: ContractEdge, source: "Vertex", target: "Vertex", status, error=None): try: monitor_service = get_monitor_service() clean_params = build_clean_params(target) diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index e898490d3..98b44fa42 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -74,9 +74,7 @@ class Graph: """Returns the state of the graph.""" return self.state_manager.get_state(name, run_id=self._run_id) - def update_state( - self, name: str, record: Union[str, Record], caller: Optional[str] = None - ) -> None: + def update_state(self, name: str, record: Union[str, Record], caller: Optional[str] = None) -> None: """Updates the state of the graph.""" if caller: # If there is a caller which is a vertex_id, I want to activate @@ -108,9 +106,7 @@ class Graph: def reset_activated_vertices(self): self.activated_vertices = [] - def append_state( - self, name: str, record: Union[str, Record], caller: Optional[str] = None - ) -> None: + def append_state(self, name: str, record: Union[str, Record], caller: Optional[str] = None) -> None: """Appends the state of the graph.""" if caller: self.activate_state_vertices(name, caller) @@ -155,10 +151,7 @@ class Graph: """Runs the graph with the given inputs.""" for vertex_id in self._is_input_vertices: vertex = self.get_vertex(vertex_id) - if input_components and ( - vertex_id not in input_components - or vertex.display_name not in input_components - ): + if input_components and (vertex_id not in input_components or vertex.display_name not in input_components): continue if vertex is None: raise ValueError(f"Vertex {vertex_id} not found") @@ -181,11 +174,7 @@ class Graph: if vertex is None: raise ValueError(f"Vertex {vertex_id} not found") - if ( - not vertex.result - and not stream - and hasattr(vertex, "consume_async_generator") - ): + if not vertex.result and not stream and hasattr(vertex, "consume_async_generator"): await vertex.consume_async_generator() if not outputs or (vertex.display_name in outputs or vertex.id in outputs): vertex_outputs.append(vertex.result) @@ -220,9 +209,7 @@ class Graph: if isinstance(_input_value, str): input_value = _input_value else: - raise ValueError( - f"Invalid input value: {input_value}. Expected string" - ) + raise ValueError(f"Invalid input value: {input_value}. Expected string") run_outputs = await self._run( inputs={INPUT_FIELD_NAME: input_value}, @@ -278,9 +265,7 @@ class Graph: def build_parent_child_map(self): parent_child_map = defaultdict(list) for vertex in self.vertices: - parent_child_map[vertex.id] = [ - child.id for child in self.get_successors(vertex) - ] + parent_child_map[vertex.id] = [child.id for child in self.get_successors(vertex)] return parent_child_map def increment_run_count(self): @@ -465,11 +450,7 @@ class Graph: """Updates the edges of a vertex.""" # Vertex has edges, so we need to update the edges for edge in vertex.edges: - if ( - edge not in self.edges - and edge.source_id in self.vertex_map - and edge.target_id in self.vertex_map - ): + if edge not in self.edges and edge.source_id in self.vertex_map and edge.target_id in self.vertex_map: self.edges.append(edge) def _build_graph(self) -> None: @@ -494,11 +475,7 @@ class Graph: return self.vertices.remove(vertex) self.vertex_map.pop(vertex_id) - self.edges = [ - edge - for edge in self.edges - if edge.source_id != vertex_id and edge.target_id != vertex_id - ] + self.edges = [edge for edge in self.edges if edge.source_id != vertex_id and edge.target_id != vertex_id] def _build_vertex_params(self) -> None: """Identifies and handles the LLM vertex within the graph.""" @@ -519,9 +496,7 @@ class Graph: return for vertex in self.vertices: if not self._validate_vertex(vertex): - raise ValueError( - f"{vertex.display_name} is not connected to any other components" - ) + raise ValueError(f"{vertex.display_name} is not connected to any other components") def _validate_vertex(self, vertex: Vertex) -> bool: """Validates a vertex.""" @@ -575,9 +550,7 @@ class Graph: name=f"{vertex.display_name} Run {vertex_task_run_count.get(vertex_id, 0)}", ) tasks.append(task) - vertex_task_run_count[vertex_id] = ( - vertex_task_run_count.get(vertex_id, 0) + 1 - ) + vertex_task_run_count[vertex_id] = vertex_task_run_count.get(vertex_id, 0) + 1 logger.debug(f"Running layer {layer_index} with {len(tasks)} tasks") await self._execute_tasks(tasks) logger.debug("Graph processing complete") @@ -619,9 +592,7 @@ class Graph: def dfs(vertex): if state[vertex] == 1: # We have a cycle - raise ValueError( - "Graph contains a cycle, cannot perform topological sort" - ) + raise ValueError("Graph contains a cycle, cannot perform topological sort") if state[vertex] == 0: state[vertex] = 1 for edge in vertex.edges: @@ -645,10 +616,7 @@ class Graph: def get_predecessors(self, vertex): """Returns the predecessors of a vertex.""" - return [ - self.get_vertex(source_id) - for source_id in self.predecessor_map.get(vertex.id, []) - ] + return [self.get_vertex(source_id) for source_id in self.predecessor_map.get(vertex.id, [])] def get_all_successors(self, vertex, recursive=True, flat=True): # Recursively get the successors of the current vertex @@ -689,10 +657,7 @@ class Graph: def get_successors(self, vertex): """Returns the successors of a vertex.""" - return [ - self.get_vertex(target_id) - for target_id in self.successor_map.get(vertex.id, []) - ] + return [self.get_vertex(target_id) for target_id in self.successor_map.get(vertex.id, [])] def get_vertex_neighbors(self, vertex: Vertex) -> Dict[Vertex, int]: """Returns the neighbors of a vertex.""" @@ -738,9 +703,7 @@ class Graph: edges_added.add((source.id, target.id)) return edges - def _get_vertex_class( - self, node_type: str, node_base_type: str, node_id: str - ) -> Type[Vertex]: + def _get_vertex_class(self, node_type: str, node_base_type: str, node_id: str) -> Type[Vertex]: """Returns the node class based on the node type.""" # First we check for the node_base_type node_name = node_id.split("-")[0] @@ -773,18 +736,14 @@ class Graph: vertex_type: str = vertex_data["type"] # type: ignore vertex_base_type: str = vertex_data["node"]["template"]["_type"] # type: ignore - VertexClass = self._get_vertex_class( - vertex_type, vertex_base_type, vertex_data["id"] - ) + VertexClass = self._get_vertex_class(vertex_type, vertex_base_type, vertex_data["id"]) vertex_instance = VertexClass(vertex, graph=self) vertex_instance.set_top_level(self.top_level_vertices) vertices.append(vertex_instance) return vertices - def get_children_by_vertex_type( - self, vertex: Vertex, vertex_type: str - ) -> List[Vertex]: + def get_children_by_vertex_type(self, vertex: Vertex, vertex_type: str) -> List[Vertex]: """Returns the children of a vertex based on the vertex type.""" children = [] vertex_types = [vertex.data["type"]] @@ -796,9 +755,7 @@ class Graph: def __repr__(self): vertex_ids = [vertex.id for vertex in self.vertices] - edges_repr = "\n".join( - [f"{edge.source_id} --> {edge.target_id}" for edge in self.edges] - ) + edges_repr = "\n".join([f"{edge.source_id} --> {edge.target_id}" for edge in self.edges]) return f"Graph:\nNodes: {vertex_ids}\nConnections:\n{edges_repr}" def sort_up_to_vertex(self, vertex_id: str, is_start: bool = False) -> List[Vertex]: @@ -866,8 +823,7 @@ class Graph: vertex.id for vertex in vertices # if filter_graphs then only vertex.is_input will be considered - if self.in_degree_map[vertex.id] == 0 - and (not filter_graphs or vertex.is_input) + if self.in_degree_map[vertex.id] == 0 and (not filter_graphs or vertex.is_input) ) layers: List[List[str]] = [] visited = set(queue) @@ -941,9 +897,7 @@ class Graph: return refined_layers - def sort_chat_inputs_first( - self, vertices_layers: List[List[str]] - ) -> List[List[str]]: + def sort_chat_inputs_first(self, vertices_layers: List[List[str]]) -> List[List[str]]: chat_inputs_first = [] for layer in vertices_layers: for vertex_id in layer: @@ -984,9 +938,7 @@ class Graph: first_layer = vertices_layers[0] # save the only the rest self.vertices_layers = vertices_layers[1:] - self.vertices_to_run = { - vertex_id for vertex_id in chain.from_iterable(vertices_layers) - } + self.vertices_to_run = {vertex_id for vertex_id in chain.from_iterable(vertices_layers)} # Return just the first layer return first_layer @@ -997,15 +949,11 @@ class Graph: self.vertices_to_run.remove(vertex_id) return should_run - def sort_interface_components_first( - self, vertices_layers: List[List[str]] - ) -> List[List[str]]: + def sort_interface_components_first(self, vertices_layers: List[List[str]]) -> List[List[str]]: """Sorts the vertices in the graph so that vertices containing ChatInput or ChatOutput come first.""" def contains_interface_component(vertex): - return any( - component.value in vertex for component in InterfaceComponentTypes - ) + return any(component.value in vertex for component in InterfaceComponentTypes) # Sort each inner list so that vertices containing ChatInput or ChatOutput come first sorted_vertices = [ @@ -1017,22 +965,16 @@ class Graph: ] return sorted_vertices - def sort_by_avg_build_time( - self, vertices_layers: List[List[str]] - ) -> List[List[str]]: + def sort_by_avg_build_time(self, vertices_layers: List[List[str]]) -> List[List[str]]: """Sorts the vertices in the graph so that vertices with the lowest average build time come first.""" def sort_layer_by_avg_build_time(vertices_ids: List[str]) -> List[str]: """Sorts the vertices in the graph so that vertices with the lowest average build time come first.""" if len(vertices_ids) == 1: return vertices_ids - vertices_ids.sort( - key=lambda vertex_id: self.get_vertex(vertex_id).avg_build_time - ) + vertices_ids.sort(key=lambda vertex_id: self.get_vertex(vertex_id).avg_build_time) return vertices_ids - sorted_vertices = [ - sort_layer_by_avg_build_time(layer) for layer in vertices_layers - ] + sorted_vertices = [sort_layer_by_avg_build_time(layer) for layer in vertices_layers] return sorted_vertices diff --git a/src/backend/langflow/graph/graph/constants.py b/src/backend/langflow/graph/graph/constants.py index 1a203849c..10c10ab07 100644 --- a/src/backend/langflow/graph/graph/constants.py +++ b/src/backend/langflow/graph/graph/constants.py @@ -46,10 +46,7 @@ class VertexTypesDict(LazyLoadDictBase): **{t: types.DocumentLoaderVertex for t in documentloader_creator.to_list()}, **{t: types.TextSplitterVertex for t in textsplitter_creator.to_list()}, **{t: types.OutputParserVertex for t in output_parser_creator.to_list()}, - **{ - t: types.CustomComponentVertex - for t in custom_component_creator.to_list() - }, + **{t: types.CustomComponentVertex for t in custom_component_creator.to_list()}, **{t: types.RetrieverVertex for t in retriever_creator.to_list()}, **{t: types.ChatVertex for t in CHAT_COMPONENTS}, **{t: types.RoutingVertex for t in ROUTING_COMPONENTS}, diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index e05f1e7a2..c0cfb116d 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -60,13 +60,8 @@ class Vertex: self.updated_raw_params = False self.id: str = data["id"] self.is_state = False - self.is_input = any( - input_component_name in self.id for input_component_name in INPUT_COMPONENTS - ) - self.is_output = any( - output_component_name in self.id - for output_component_name in OUTPUT_COMPONENTS - ) + self.is_input = any(input_component_name in self.id for input_component_name in INPUT_COMPONENTS) + self.is_output = any(output_component_name in self.id for output_component_name in OUTPUT_COMPONENTS) self.has_session_id = None self._custom_component = None self.has_external_input = False @@ -106,17 +101,11 @@ class Vertex: def set_state(self, state: str): self.state = VertexStates[state] - if ( - self.state == VertexStates.INACTIVE - and self.graph.in_degree_map[self.id] < 2 - ): + if self.state == VertexStates.INACTIVE and self.graph.in_degree_map[self.id] < 2: # If the vertex is inactive and has only one in degree # it means that it is not a merge point in the graph self.graph.inactivated_vertices.add(self.id) - elif ( - self.state == VertexStates.ACTIVE - and self.id in self.graph.inactivated_vertices - ): + elif self.state == VertexStates.ACTIVE and self.id in self.graph.inactivated_vertices: self.graph.inactivated_vertices.remove(self.id) @property @@ -133,9 +122,7 @@ class Vertex: # If the Vertex.type is a power component # then we need to return the built object # instead of the result dict - if self.is_interface_component and not isinstance( - self._built_object, UnbuiltObject - ): + if self.is_interface_component and not isinstance(self._built_object, UnbuiltObject): result = self._built_object # if it is not a dict or a string and hasattr model_dump then # return the model_dump @@ -147,11 +134,7 @@ class Vertex: if isinstance(self._built_result, UnbuiltResult): return {} - return ( - self._built_result - if isinstance(self._built_result, dict) - else {"result": self._built_result} - ) + return self._built_result if isinstance(self._built_result, dict) else {"result": self._built_result} def set_artifacts(self) -> None: pass @@ -221,31 +204,19 @@ class Vertex: self.selected_output_type = self.data["node"].get("selected_output_type") self.is_input = self.data["node"].get("is_input") or self.is_input self.is_output = self.data["node"].get("is_output") or self.is_output - template_dicts = { - key: value - for key, value in self.data["node"]["template"].items() - if isinstance(value, dict) - } + template_dicts = {key: value for key, value in self.data["node"]["template"].items() if isinstance(value, dict)} self.has_session_id = "session_id" in template_dicts self.required_inputs = [ - template_dicts[key]["type"] - for key, value in template_dicts.items() - if value["required"] + template_dicts[key]["type"] for key, value in template_dicts.items() if value["required"] ] self.optional_inputs = [ - template_dicts[key]["type"] - for key, value in template_dicts.items() - if not value["required"] + template_dicts[key]["type"] for key, value in template_dicts.items() if not value["required"] ] # Add the template_dicts[key]["input_types"] to the optional_inputs self.optional_inputs.extend( - [ - input_type - for value in template_dicts.values() - for input_type in value.get("input_types", []) - ] + [input_type for value in template_dicts.values() for input_type in value.get("input_types", [])] ) template_dict = self.data["node"]["template"] @@ -292,11 +263,7 @@ class Vertex: self.updated_raw_params = False return - template_dict = { - key: value - for key, value in self.data["node"]["template"].items() - if isinstance(value, dict) - } + template_dict = {key: value for key, value in self.data["node"]["template"].items() if isinstance(value, dict)} params = {} for edge in self.edges: @@ -317,10 +284,7 @@ class Vertex: # we don't know the key of the dict but we need to set the value # to the vertex that is the source of the edge param_dict = template_dict[param_key]["value"] - params[param_key] = { - key: self.graph.get_vertex(edge.source_id) - for key in param_dict.keys() - } + params[param_key] = {key: self.graph.get_vertex(edge.source_id) for key in param_dict.keys()} else: params[param_key] = self.graph.get_vertex(edge.source_id) @@ -356,11 +320,7 @@ class Vertex: # list of dicts, so we need to convert it to a dict # before passing it to the build method if isinstance(val, list): - params[key] = { - k: v - for item in value.get("value", []) - for k, v in item.items() - } + params[key] = {k: v for item in value.get("value", []) for k, v in item.items()} elif isinstance(val, dict): params[key] = val elif value.get("type") == "int" and val is not None: @@ -485,9 +445,7 @@ class Vertex: if isinstance(self._built_object, str): self._built_result = self._built_object - result = await generate_result( - self._built_object, inputs, self.has_external_output, session_id - ) + result = await generate_result(self._built_object, inputs, self.has_external_output, session_id) self._built_result = result async def _build_each_node_in_params_dict(self, user_id=None): @@ -507,9 +465,7 @@ class Vertex: elif key not in self.params or self.updated_raw_params: self.params[key] = value - async def _build_dict_and_update_params( - self, key, nodes_dict: Dict[str, "Vertex"], user_id=None - ): + async def _build_dict_and_update_params(self, key, nodes_dict: Dict[str, "Vertex"], user_id=None): """ Iterates over a dictionary of nodes, builds each and updates the params dictionary. """ @@ -532,9 +488,7 @@ class Vertex: """ return all(self._is_node(node) for node in value) - async def get_result( - self, requester: Optional["Vertex"] = None, user_id=None, timeout=None - ) -> Any: + async def get_result(self, requester: Optional["Vertex"] = None, user_id=None, timeout=None) -> Any: # PLEASE REVIEW THIS IF STATEMENT # Check if the Vertex was built already if self._built: @@ -568,9 +522,7 @@ class Vertex: self._extend_params_list_with_result(key, result) self.params[key] = result - async def _build_list_of_nodes_and_update_params( - self, key, nodes: List["Vertex"], user_id=None - ): + async def _build_list_of_nodes_and_update_params(self, key, nodes: List["Vertex"], user_id=None): """ Iterates over a list of nodes, builds each and updates the params dictionary. """ @@ -637,9 +589,7 @@ class Vertex: except Exception as exc: logger.exception(exc) - raise ValueError( - f"Error building node {self.display_name}: {str(exc)}" - ) from exc + raise ValueError(f"Error building node {self.display_name}: {str(exc)}") from exc def _update_built_object_and_artifacts(self, result): """ @@ -667,9 +617,7 @@ class Vertex: logger.warning(message) elif isinstance(self._built_object, (Iterator, AsyncIterator)): if self.display_name in ["Text Output"]: - raise ValueError( - f"You are trying to stream to a {self.display_name}. Try using a Chat Output instead." - ) + raise ValueError(f"You are trying to stream to a {self.display_name}. Try using a Chat Output instead.") def _reset(self, params_update: Optional[Dict[str, Any]] = None): self._built = False @@ -732,24 +680,16 @@ class Vertex: return self._built_object # Get the requester edge - requester_edge = next( - (edge for edge in self.edges if edge.target_id == requester.id), None - ) + requester_edge = next((edge for edge in self.edges if edge.target_id == requester.id), None) # Return the result of the requester edge - return ( - None - if requester_edge is None - else await requester_edge.get_result(source=self, target=requester) - ) + return None if requester_edge is None else await requester_edge.get_result(source=self, target=requester) def add_edge(self, edge: "ContractEdge") -> None: if edge not in self.edges: self.edges.append(edge) def __repr__(self) -> str: - return ( - f"Vertex(display_name={self.display_name}, id={self.id}, data={self.data})" - ) + return f"Vertex(display_name={self.display_name}, id={self.id}, data={self.data})" def __eq__(self, __o: object) -> bool: try: @@ -770,8 +710,4 @@ class Vertex: def _built_object_repr(self): # Add a message with an emoji, stars for sucess, - return ( - "Built sucessfully ✨" - if self._built_object is not None - else "Failed to build 😵‍💫" - ) + return "Built sucessfully ✨" if self._built_object is not None else "Failed to build 😵‍💫" diff --git a/src/backend/langflow/graph/vertex/types.py b/src/backend/langflow/graph/vertex/types.py index 99791729f..de2677d41 100644 --- a/src/backend/langflow/graph/vertex/types.py +++ b/src/backend/langflow/graph/vertex/types.py @@ -123,11 +123,9 @@ class DocumentLoaderVertex(Vertex): # show how many documents are in the list? if not isinstance(self._built_object, UnbuiltObject): - avg_length = sum( - len(record.text) - for record in self._built_object - if hasattr(record, "text") - ) / len(self._built_object) + avg_length = sum(len(record.text) for record in self._built_object if hasattr(record, "text")) / len( + self._built_object + ) return f"""{self.display_name}({len(self._built_object)} records) \nAvg. Record Length (characters): {int(avg_length)} Records: {self._built_object[:3]}...""" @@ -200,9 +198,7 @@ class TextSplitterVertex(Vertex): # show how many documents are in the list? if not isinstance(self._built_object, UnbuiltObject): - avg_length = sum(len(doc.page_content) for doc in self._built_object) / len( - self._built_object - ) + avg_length = sum(len(doc.page_content) for doc in self._built_object) / len(self._built_object) return f"""{self.vertex_type}({len(self._built_object)} documents) \nAvg. Document Length (characters): {int(avg_length)} \nDocuments: {self._built_object[:3]}...""" @@ -249,27 +245,18 @@ class PromptVertex(Vertex): user_id = kwargs.get("user_id", None) tools = kwargs.get("tools", []) if not self._built or force: - if ( - "input_variables" not in self.params - or self.params["input_variables"] is None - ): + if "input_variables" not in self.params or self.params["input_variables"] is None: self.params["input_variables"] = [] # Check if it is a ZeroShotPrompt and needs a tool if "ShotPrompt" in self.vertex_type: - tools = ( - [tool_node.build(user_id=user_id) for tool_node in tools] - if tools is not None - else [] - ) + tools = [tool_node.build(user_id=user_id) for tool_node in tools] if tools is not None else [] # flatten the list of tools if it is a list of lists # first check if it is a list if tools and isinstance(tools, list) and isinstance(tools[0], list): tools = flatten_list(tools) self.params["tools"] = tools prompt_params = [ - key - for key, value in self.params.items() - if isinstance(value, str) and key != "format_instructions" + key for key, value in self.params.items() if isinstance(value, str) and key != "format_instructions" ] else: prompt_params = ["template"] @@ -279,20 +266,14 @@ class PromptVertex(Vertex): prompt_text = self.params[param] variables = extract_input_variables_from_prompt(prompt_text) self.params["input_variables"].extend(variables) - self.params["input_variables"] = list( - set(self.params["input_variables"]) - ) + self.params["input_variables"] = list(set(self.params["input_variables"])) elif isinstance(self.params, dict): self.params.pop("input_variables", None) await self._build(user_id=user_id) def _built_object_repr(self): - if ( - not self.artifacts - or self._built_object is None - or not hasattr(self._built_object, "format") - ): + if not self.artifacts or self._built_object is None or not hasattr(self._built_object, "format"): return super()._built_object_repr() elif isinstance(self._built_object, UnbuiltObject): return super()._built_object_repr() @@ -304,9 +285,7 @@ class PromptVertex(Vertex): # so the prompt format doesn't break artifacts.pop("handle_keys", None) try: - if not hasattr(self._built_object, "template") and hasattr( - self._built_object, "prompt" - ): + if not hasattr(self._built_object, "template") and hasattr(self._built_object, "prompt"): template = self._built_object.prompt.template else: template = self._built_object.template @@ -314,11 +293,7 @@ class PromptVertex(Vertex): if value: replace_key = "{" + key + "}" template = template.replace(replace_key, value) - return ( - template - if isinstance(template, str) - else f"{self.vertex_type}({template})" - ) + return template if isinstance(template, str) else f"{self.vertex_type}({template})" except KeyError: return str(self._built_object) diff --git a/src/backend/langflow/initial_setup/setup.py b/src/backend/langflow/initial_setup/setup.py index 75c827707..692ea77d4 100644 --- a/src/backend/langflow/initial_setup/setup.py +++ b/src/backend/langflow/initial_setup/setup.py @@ -18,10 +18,7 @@ STARTER_FOLDER_NAME = "Starter Projects" # can use them as a starting point for their own projects. -def update_projects_components_with_latest_component_versions( - project_data, all_types_dict -): - +def update_projects_components_with_latest_component_versions(project_data, all_types_dict): # project data has a nodes key, which is a list of nodes # we want to run through each node and see if it exists in the all_types_dict # if so, we go into the template key and also get the template from all_types_dict @@ -148,13 +145,9 @@ def create_or_update_starter_projects(): project_icon, project_icon_bg_color, ) = get_project_data(project) - project_data = update_projects_components_with_latest_component_versions( - project_data, all_types_dict - ) + project_data = update_projects_components_with_latest_component_versions(project_data, all_types_dict) if project_name and project_data: - for existing_project in get_all_flows_similar_to_project( - session, project_name - ): + for existing_project in get_all_flows_similar_to_project(session, project_name): session.delete(existing_project) create_new_project( diff --git a/src/backend/langflow/interface/custom/code_parser/code_parser.py b/src/backend/langflow/interface/custom/code_parser/code_parser.py index 1b4bfaf39..55a2c693f 100644 --- a/src/backend/langflow/interface/custom/code_parser/code_parser.py +++ b/src/backend/langflow/interface/custom/code_parser/code_parser.py @@ -99,9 +99,7 @@ class CodeParser: elif isinstance(node, ast.ImportFrom): for alias in node.names: if alias.asname: - self.data["imports"].append( - (node.module, f"{alias.name} as {alias.asname}") - ) + self.data["imports"].append((node.module, f"{alias.name} as {alias.asname}")) else: self.data["imports"].append((node.module, alias.name)) @@ -150,9 +148,7 @@ class CodeParser: return_type = None if node.returns: return_type_str = ast.unparse(node.returns) - eval_env = self.construct_eval_env( - return_type_str, tuple(self.data["imports"]) - ) + eval_env = self.construct_eval_env(return_type_str, tuple(self.data["imports"])) try: return_type = eval(return_type_str, eval_env) @@ -194,22 +190,14 @@ class CodeParser: num_defaults = len(node.args.defaults) num_missing_defaults = num_args - num_defaults missing_defaults = [MissingDefault()] * num_missing_defaults - default_values = [ - ast.unparse(default).strip("'") if default else None - for default in node.args.defaults - ] + default_values = [ast.unparse(default).strip("'") if default else None for default in node.args.defaults] # Now check all default values to see if there # are any "None" values in the middle - default_values = [ - None if value == "None" else value for value in default_values - ] + default_values = [None if value == "None" else value for value in default_values] defaults = missing_defaults + default_values - args = [ - self.parse_arg(arg, default) - for arg, default in zip(node.args.args, defaults) - ] + args = [self.parse_arg(arg, default) for arg, default in zip(node.args.args, defaults)] return args def parse_varargs(self, node: ast.FunctionDef) -> List[Dict[str, Any]]: @@ -227,17 +215,11 @@ class CodeParser: """ Parses the keyword-only arguments of a function or method node. """ - kw_defaults = [None] * ( - len(node.args.kwonlyargs) - len(node.args.kw_defaults) - ) + [ - ast.unparse(default) if default else None - for default in node.args.kw_defaults + kw_defaults = [None] * (len(node.args.kwonlyargs) - len(node.args.kw_defaults)) + [ + ast.unparse(default) if default else None for default in node.args.kw_defaults ] - args = [ - self.parse_arg(arg, default) - for arg, default in zip(node.args.kwonlyargs, kw_defaults) - ] + args = [self.parse_arg(arg, default) for arg, default in zip(node.args.kwonlyargs, kw_defaults)] return args def parse_kwargs(self, node: ast.FunctionDef) -> List[Dict[str, Any]]: @@ -341,9 +323,7 @@ class CodeParser: Extracts global variables from the code. """ global_var = { - "targets": [ - t.id if hasattr(t, "id") else ast.dump(t) for t in node.targets - ], + "targets": [t.id if hasattr(t, "id") else ast.dump(t) for t in node.targets], "value": ast.unparse(node.value), } self.data["global_vars"].append(global_var) diff --git a/src/backend/langflow/interface/custom/custom_component/custom_component.py b/src/backend/langflow/interface/custom/custom_component/custom_component.py index d939d33ef..0b45eb9d2 100644 --- a/src/backend/langflow/interface/custom/custom_component/custom_component.py +++ b/src/backend/langflow/interface/custom/custom_component/custom_component.py @@ -80,9 +80,7 @@ class CustomComponent(Component): if not self.vertex: raise ValueError("Vertex is not set") try: - self.vertex.graph.update_state( - name=name, record=value, caller=self.vertex.id - ) + self.vertex.graph.update_state(name=name, record=value, caller=self.vertex.id) except Exception as e: raise ValueError(f"Error updating state: {e}") @@ -90,9 +88,7 @@ class CustomComponent(Component): if not self.vertex: raise ValueError("Vertex is not set") try: - self.vertex.graph.append_state( - name=name, record=value, caller=self.vertex.id - ) + self.vertex.graph.append_state(name=name, record=value, caller=self.vertex.id) except Exception as e: raise ValueError(f"Error appending state: {e}") @@ -158,9 +154,7 @@ class CustomComponent(Component): def tree(self): return self.get_code_tree(self.code or "") - def to_records( - self, data: Any, keys: Optional[List[str]] = None, silent_errors: bool = False - ) -> List[Record]: + def to_records(self, data: Any, keys: Optional[List[str]] = None, silent_errors: bool = False) -> List[Record]: """ Converts input data into a list of Record objects. @@ -211,9 +205,7 @@ class CustomComponent(Component): return records - def create_references_from_records( - self, records: List[Record], include_data: bool = False - ) -> str: + def create_references_from_records(self, records: List[Record], include_data: bool = False) -> str: """ Create references from a list of records. @@ -252,20 +244,14 @@ class CustomComponent(Component): if not self.code: return {} - component_classes = [ - cls - for cls in self.tree["classes"] - if self.code_class_base_inheritance in cls["bases"] - ] + component_classes = [cls for cls in self.tree["classes"] if self.code_class_base_inheritance in cls["bases"]] if not component_classes: return {} # Assume the first Component class is the one we're interested in component_class = component_classes[0] build_methods = [ - method - for method in component_class["methods"] - if method["name"] == self.function_entrypoint_name + method for method in component_class["methods"] if method["name"] == self.function_entrypoint_name ] return build_methods[0] if build_methods else {} @@ -322,9 +308,7 @@ class CustomComponent(Component): # Retrieve and decrypt the credential by name for the current user db_service = get_db_service() with session_getter(db_service) as session: - return credential_service.get_credential( - user_id=self._user_id or "", name=name, session=session - ) + return credential_service.get_credential(user_id=self._user_id or "", name=name, session=session) return get_credential @@ -334,9 +318,7 @@ class CustomComponent(Component): credential_service = get_credential_service() db_service = get_db_service() with session_getter(db_service) as session: - return credential_service.list_credentials( - user_id=self._user_id, session=session - ) + return credential_service.list_credentials(user_id=self._user_id, session=session) def index(self, value: int = 0): """Returns a function that returns the value at the given index in the iterable.""" @@ -375,11 +357,7 @@ class CustomComponent(Component): if not self._flows_records: self.list_flows() if not flow_id and self._flows_records: - flow_ids = [ - flow.data["id"] - for flow in self._flows_records - if flow.data["name"] == flow_name - ] + flow_ids = [flow.data["id"] for flow in self._flows_records if flow.data["name"] == flow_name] if not flow_ids: raise ValueError(f"Flow {flow_name} not found") elif len(flow_ids) > 1: @@ -401,9 +379,7 @@ class CustomComponent(Component): db_service = get_db_service() with get_session(db_service) as session: flows = session.exec( - select(Flow) - .where(Flow.user_id == self._user_id) - .where(Flow.is_component == False) # noqa + select(Flow).where(Flow.user_id == self._user_id).where(Flow.is_component == False) # noqa ).all() flows_records = [flow.to_record() for flow in flows] diff --git a/src/backend/langflow/interface/custom/utils.py b/src/backend/langflow/interface/custom/utils.py index df63f2c12..1059b1503 100644 --- a/src/backend/langflow/interface/custom/utils.py +++ b/src/backend/langflow/interface/custom/utils.py @@ -34,18 +34,14 @@ class UpdateBuildConfigError(Exception): pass -def add_output_types( - frontend_node: CustomComponentFrontendNode, return_types: List[str] -): +def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]): """Add output types to the frontend node""" for return_type in return_types: if return_type is None: raise HTTPException( status_code=400, detail={ - "error": ( - "Invalid return type. Please check your code and try again." - ), + "error": ("Invalid return type. Please check your code and try again."), "traceback": traceback.format_exc(), }, ) @@ -77,18 +73,14 @@ def reorder_fields(frontend_node: CustomComponentFrontendNode, field_order: List frontend_node.field_order = field_order -def add_base_classes( - frontend_node: CustomComponentFrontendNode, return_types: List[str] -): +def add_base_classes(frontend_node: CustomComponentFrontendNode, return_types: List[str]): """Add base classes to the frontend node""" for return_type_instance in return_types: if return_type_instance is None: raise HTTPException( status_code=400, detail={ - "error": ( - "Invalid return type. Please check your code and try again." - ), + "error": ("Invalid return type. Please check your code and try again."), "traceback": traceback.format_exc(), }, ) @@ -123,9 +115,7 @@ def get_field_properties(extra_field): # a required field is a field that does not contain # optional in field_type # and a field that does not have a default value - field_required = "optional" not in field_type.lower() and isinstance( - field_value, MissingDefault - ) + field_required = "optional" not in field_type.lower() and isinstance(field_value, MissingDefault) field_value = field_value if not isinstance(field_value, MissingDefault) else None if not field_required: @@ -171,14 +161,10 @@ def add_new_custom_field( # If options is a list, then it's a dropdown # If options is None, then it's a list of strings is_list = isinstance(field_config.get("options"), list) - field_config["is_list"] = ( - is_list or field_config.get("list", False) or field_contains_list - ) + field_config["is_list"] = is_list or field_config.get("list", False) or field_contains_list if "name" in field_config: - warnings.warn( - "The 'name' key in field_config is used to build the object and can't be changed." - ) + warnings.warn("The 'name' key in field_config is used to build the object and can't be changed.") required = field_config.pop("required", field_required) placeholder = field_config.pop("placeholder", "") @@ -217,9 +203,7 @@ def add_extra_fields(frontend_node, field_config, function_args): ]: continue - field_name, field_type, field_value, field_required = get_field_properties( - extra_field - ) + field_name, field_type, field_value, field_required = get_field_properties(extra_field) config = _field_config.pop(field_name, {}) frontend_node = add_new_custom_field( frontend_node, @@ -229,17 +213,13 @@ def add_extra_fields(frontend_node, field_config, function_args): field_required, config, ) - if "kwargs" in function_args_names and not all( - key in function_args_names for key in field_config.keys() - ): + if "kwargs" in function_args_names and not all(key in function_args_names for key in field_config.keys()): for field_name, field_config in _field_config.copy().items(): if "name" not in field_config or field_name == "code": continue config = _field_config.get(field_name, {}) config = config.model_dump() if isinstance(config, BaseModel) else config - field_name, field_type, field_value, field_required = get_field_properties( - extra_field=config - ) + field_name, field_type, field_value, field_required = get_field_properties(extra_field=config) frontend_node = add_new_custom_field( frontend_node, field_name, @@ -277,9 +257,7 @@ def run_build_config( raise HTTPException( status_code=400, detail={ - "error": ( - "Invalid type convertion. Please check your code and try again." - ), + "error": ("Invalid type convertion. Please check your code and try again."), "traceback": traceback.format_exc(), }, ) from exc @@ -329,7 +307,6 @@ def run_build_config( return build_config, custom_instance except Exception as exc: - logger.error(f"Error while building field config: {str(exc)}") if hasattr(exc, "detail") and "traceback" in exc.detail: logger.error(exc.detail["traceback"]) @@ -358,7 +335,6 @@ def build_frontend_node(template_config): def add_code_field(frontend_node: CustomComponentFrontendNode, raw_code, field_config): - code_field = TemplateField( dynamic=True, required=True, @@ -397,16 +373,10 @@ def build_custom_component_template( add_extra_fields(frontend_node, field_config, entrypoint_args) - frontend_node = add_code_field( - frontend_node, custom_component.code, field_config.get("code", {}) - ) + frontend_node = add_code_field(frontend_node, custom_component.code, field_config.get("code", {})) - add_base_classes( - frontend_node, custom_component.get_function_entrypoint_return_type - ) - add_output_types( - frontend_node, custom_component.get_function_entrypoint_return_type - ) + add_base_classes(frontend_node, custom_component.get_function_entrypoint_return_type) + add_output_types(frontend_node, custom_component.get_function_entrypoint_return_type) reorder_fields(frontend_node, custom_instance._get_field_order()) @@ -417,9 +387,7 @@ def build_custom_component_template( raise HTTPException( status_code=400, detail={ - "error": ( - f"Something went wrong while building the custom component. Hints: {str(exc)}" - ), + "error": (f"Something went wrong while building the custom component. Hints: {str(exc)}"), "traceback": traceback.format_exc(), }, ) from exc @@ -455,9 +423,7 @@ def build_custom_components(components_paths: List[str]): custom_component_dict = build_custom_component_list_from_path(path_str) if custom_component_dict: category = next(iter(custom_component_dict)) - logger.info( - f"Loading {len(custom_component_dict[category])} component(s) from category {category}" - ) + logger.info(f"Loading {len(custom_component_dict[category])} component(s) from category {category}") custom_components_from_file = merge_nested_dicts_with_renaming( custom_components_from_file, custom_component_dict ) @@ -492,9 +458,7 @@ def update_field_dict( build_config = dd_build_config except Exception as exc: logger.error(f"Error while running update_build_config: {str(exc)}") - raise UpdateBuildConfigError( - f"Error while running update_build_config: {str(exc)}" - ) from exc + raise UpdateBuildConfigError(f"Error while running update_build_config: {str(exc)}") from exc # Let's check if "range_spec" is a RangeSpec object if "rangeSpec" in field_dict and isinstance(field_dict["rangeSpec"], RangeSpec): diff --git a/src/backend/langflow/interface/initialize/loading.py b/src/backend/langflow/interface/initialize/loading.py index b21e45d41..554fd99d7 100644 --- a/src/backend/langflow/interface/initialize/loading.py +++ b/src/backend/langflow/interface/initialize/loading.py @@ -145,13 +145,9 @@ async def instantiate_based_on_type( return class_object(**params) -async def instantiate_custom_component( - node_type, class_object, params, user_id, vertex -): +async def instantiate_custom_component(node_type, class_object, params, user_id, vertex): params_copy = params.copy() - class_object: Type["CustomComponent"] = eval_custom_component_code( - params_copy.pop("code") - ) + class_object: Type["CustomComponent"] = eval_custom_component_code(params_copy.pop("code")) custom_component: "CustomComponent" = class_object( user_id=user_id, parameters=params_copy, @@ -227,9 +223,7 @@ def instantiate_memory(node_type, class_object, params): # I want to catch a specific attribute error that happens # when the object does not have a cursor attribute except Exception as exc: - if "object has no attribute 'cursor'" in str( - exc - ) or 'object has no field "conn"' in str(exc): + if "object has no attribute 'cursor'" in str(exc) or 'object has no field "conn"' in str(exc): raise AttributeError( ( "Failed to build connection to database." @@ -272,9 +266,7 @@ def instantiate_agent(node_type, class_object: Type[agent_module.Agent], params: if class_method := getattr(class_object, method, None): agent = class_method(**params) tools = params.get("tools", []) - return AgentExecutor.from_agent_and_tools( - agent=agent, tools=tools, handle_parsing_errors=True - ) + return AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, handle_parsing_errors=True) return load_agent_executor(class_object, params) @@ -330,11 +322,7 @@ def instantiate_embedding(node_type, class_object, params: Dict): try: return class_object(**params) except ValidationError: - params = { - key: value - for key, value in params.items() - if key in class_object.model_fields - } + params = {key: value for key, value in params.items() if key in class_object.model_fields} return class_object(**params) @@ -346,9 +334,7 @@ def instantiate_vectorstore(class_object: Type[VectorStore], params: Dict): if "texts" in params: params["documents"] = params.pop("texts") if "documents" in params: - params["documents"] = [ - doc for doc in params["documents"] if isinstance(doc, Document) - ] + params["documents"] = [doc for doc in params["documents"] if isinstance(doc, Document)] if initializer := vecstore_initializer.get(class_object.__name__): vecstore = initializer(class_object, params) else: @@ -363,9 +349,7 @@ def instantiate_vectorstore(class_object: Type[VectorStore], params: Dict): return vecstore -def instantiate_documentloader( - node_type: str, class_object: Type[BaseLoader], params: Dict -): +def instantiate_documentloader(node_type: str, class_object: Type[BaseLoader], params: Dict): if "file_filter" in params: # file_filter will be a string but we need a function # that will be used to filter the files using file_filter @@ -374,17 +358,13 @@ def instantiate_documentloader( # in x and if it is, we will return True file_filter = params.pop("file_filter") extensions = file_filter.split(",") - params["file_filter"] = lambda x: any( - extension.strip() in x for extension in extensions - ) + params["file_filter"] = lambda x: any(extension.strip() in x for extension in extensions) metadata = params.pop("metadata", None) if metadata and isinstance(metadata, str): try: metadata = orjson.loads(metadata) except json.JSONDecodeError as exc: - raise ValueError( - "The metadata you provided is not a valid JSON string." - ) from exc + raise ValueError("The metadata you provided is not a valid JSON string.") from exc if node_type == "WebBaseLoader": if web_path := params.pop("web_path", None): @@ -417,9 +397,7 @@ def instantiate_textsplitter( "Try changing the chunk_size of the Text Splitter." ) from exc - if ( - "separator_type" in params and params["separator_type"] == "Text" - ) or "separator_type" not in params: + if ("separator_type" in params and params["separator_type"] == "Text") or "separator_type" not in params: params.pop("separator_type", None) # separators might come in as an escaped string like \\n # so we need to convert it to a string @@ -427,9 +405,7 @@ def instantiate_textsplitter( if isinstance(params["separators"], str): params["separators"] = unescape_string(params["separators"]) elif isinstance(params["separators"], list): - params["separators"] = [ - unescape_string(separator) for separator in params["separators"] - ] + params["separators"] = [unescape_string(separator) for separator in params["separators"]] text_splitter = class_object(**params) else: from langchain.text_splitter import Language @@ -456,8 +432,7 @@ def replace_zero_shot_prompt_with_prompt_template(nodes): tools = [ tool for tool in nodes - if tool["type"] != "chatOutputNode" - and "Tool" in tool["data"]["node"]["base_classes"] + if tool["type"] != "chatOutputNode" and "Tool" in tool["data"]["node"]["base_classes"] ] node["data"] = build_prompt_template(prompt=node["data"], tools=tools) break @@ -471,9 +446,7 @@ def load_agent_executor(agent_class: type[agent_module.Agent], params, **kwargs) # agent has hidden args for memory. might need to be support # memory = params["memory"] # if allowed_tools is not a list or set, make it a list - if not isinstance(allowed_tools, (list, set)) and isinstance( - allowed_tools, BaseTool - ): + if not isinstance(allowed_tools, (list, set)) and isinstance(allowed_tools, BaseTool): allowed_tools = [allowed_tools] tool_names = [tool.name for tool in allowed_tools] # Agent class requires an output_parser but Agent classes @@ -501,10 +474,7 @@ def build_prompt_template(prompt, tools): format_instructions = prompt["node"]["template"]["format_instructions"]["value"] tool_strings = "\n".join( - [ - f"{tool['data']['node']['name']}: {tool['data']['node']['description']}" - for tool in tools - ] + [f"{tool['data']['node']['name']}: {tool['data']['node']['description']}" for tool in tools] ) tool_names = ", ".join([tool["data"]["node"]["name"] for tool in tools]) format_instructions = format_instructions.format(tool_names=tool_names) diff --git a/src/backend/langflow/interface/types.py b/src/backend/langflow/interface/types.py index 4908a60e3..f1f315700 100644 --- a/src/backend/langflow/interface/types.py +++ b/src/backend/langflow/interface/types.py @@ -66,12 +66,8 @@ def build_langchain_types_dict(): # sourcery skip: dict-assign-update-to-union def get_all_types_dict(components_paths): """Get all types dictionary combining native and custom components.""" native_components = build_langchain_types_dict() - custom_components_from_file = build_custom_components( - components_paths=components_paths - ) - return merge_nested_dicts_with_renaming( - native_components, custom_components_from_file - ) + custom_components_from_file = build_custom_components(components_paths=components_paths) + return merge_nested_dicts_with_renaming(native_components, custom_components_from_file) def get_all_components(components_paths, as_dict=False): diff --git a/src/backend/langflow/processing/load.py b/src/backend/langflow/processing/load.py index 00b1ea3ec..562a37d08 100644 --- a/src/backend/langflow/processing/load.py +++ b/src/backend/langflow/processing/load.py @@ -6,9 +6,7 @@ from langflow.graph import Graph from langflow.processing.process import process_tweaks -def load_flow_from_json( - flow: Union[Path, str, dict], tweaks: Optional[dict] = None -) -> Graph: +def load_flow_from_json(flow: Union[Path, str, dict], tweaks: Optional[dict] = None) -> Graph: """ Load flow from a JSON file or a JSON object. @@ -25,9 +23,7 @@ def load_flow_from_json( elif isinstance(flow, dict): flow_graph = flow else: - raise TypeError( - "Input must be either a file path (str) or a JSON object (dict)" - ) + raise TypeError("Input must be either a file path (str) or a JSON object (dict)") graph_data = flow_graph["data"] if tweaks is not None: diff --git a/src/backend/langflow/processing/process.py b/src/backend/langflow/processing/process.py index e583a081b..49053e572 100644 --- a/src/backend/langflow/processing/process.py +++ b/src/backend/langflow/processing/process.py @@ -129,9 +129,7 @@ async def process_runnable(runnable: Runnable, inputs: Union[dict, List[dict]]): elif isinstance(inputs, dict) and hasattr(runnable, "ainvoke"): result = await runnable.ainvoke(inputs) else: - raise ValueError( - f"Runnable {runnable} does not support inputs of type {type(inputs)}" - ) + raise ValueError(f"Runnable {runnable} does not support inputs of type {type(inputs)}") # Check if the result is a list of AIMessages if isinstance(result, list) and all(isinstance(r, AIMessage) for r in result): result = [r.content for r in result] @@ -140,9 +138,7 @@ async def process_runnable(runnable: Runnable, inputs: Union[dict, List[dict]]): return result -async def process_inputs_dict( - built_object: Union[Chain, VectorStore, Runnable], inputs: dict -): +async def process_inputs_dict(built_object: Union[Chain, VectorStore, Runnable], inputs: dict): if isinstance(built_object, Chain): if inputs is None: raise ValueError("Inputs must be provided for a Chain") @@ -177,9 +173,7 @@ async def process_inputs_list(built_object: Runnable, inputs: List[dict]): return await process_runnable(built_object, inputs) -async def generate_result( - built_object: Union[Chain, VectorStore, Runnable], inputs: Union[dict, List[dict]] -): +async def generate_result(built_object: Union[Chain, VectorStore, Runnable], inputs: Union[dict, List[dict]]): if isinstance(inputs, dict): result = await process_inputs_dict(built_object, inputs) elif isinstance(inputs, List) and isinstance(built_object, Runnable): @@ -218,9 +212,7 @@ async def run_graph( else: graph_data = graph._graph_data if session_id is None and session_service is not None: - session_id = session_service.generate_key( - session_id=flow_id, data_graph=graph_data - ) + session_id = session_service.generate_key(session_id=flow_id, data_graph=graph_data) if inputs is None: inputs = [{}] @@ -244,9 +236,7 @@ def validate_input( nodes = graph_data.get("data", {}).get("nodes") or graph_data.get("nodes") if not isinstance(nodes, list): - raise ValueError( - "graph_data should contain a list of nodes under 'data' key or directly under 'nodes' key" - ) + raise ValueError("graph_data should contain a list of nodes under 'data' key or directly under 'nodes' key") return nodes @@ -255,9 +245,7 @@ def apply_tweaks(node: Dict[str, Any], node_tweaks: Dict[str, Any]) -> None: template_data = node.get("data", {}).get("node", {}).get("template") if not isinstance(template_data, dict): - logger.warning( - f"Template data for node {node.get('id')} should be a dictionary" - ) + logger.warning(f"Template data for node {node.get('id')} should be a dictionary") return for tweak_name, tweak_value in node_tweaks.items(): @@ -272,9 +260,7 @@ def apply_tweaks_on_vertex(vertex: Vertex, node_tweaks: Dict[str, Any]) -> None: vertex.params[tweak_name] = tweak_value -def process_tweaks( - graph_data: Dict[str, Any], tweaks: Union["Tweaks", Dict[str, Dict[str, Any]]] -) -> Dict[str, Any]: +def process_tweaks(graph_data: Dict[str, Any], tweaks: Union["Tweaks", Dict[str, Dict[str, Any]]]) -> Dict[str, Any]: """ This function is used to tweak the graph data using the node id and the tweaks dict. @@ -310,8 +296,6 @@ def process_tweaks_on_graph(graph: Graph, tweaks: Dict[str, Dict[str, Any]]): if node_tweaks := tweaks.get(node_id): apply_tweaks_on_vertex(vertex, node_tweaks) else: - logger.warning( - "Each node should be a Vertex with an 'id' attribute of type str" - ) + logger.warning("Each node should be a Vertex with an 'id' attribute of type str") return graph diff --git a/src/backend/langflow/schema/schema.py b/src/backend/langflow/schema/schema.py index 077c20cf5..8fd50d633 100644 --- a/src/backend/langflow/schema/schema.py +++ b/src/backend/langflow/schema/schema.py @@ -63,9 +63,7 @@ class Record(BaseModel): return self.data.get(key, self._default_value) except KeyError: # Fallback to default behavior to raise AttributeError for undefined attributes - raise AttributeError( - f"'{type(self).__name__}' object has no attribute '{key}'" - ) + raise AttributeError(f"'{type(self).__name__}' object has no attribute '{key}'") def __setattr__(self, key, value): """ diff --git a/src/backend/langflow/services/database/models/flow/model.py b/src/backend/langflow/services/database/models/flow/model.py index 7352d63dc..8a97e97a1 100644 --- a/src/backend/langflow/services/database/models/flow/model.py +++ b/src/backend/langflow/services/database/models/flow/model.py @@ -22,9 +22,7 @@ class FlowBase(SQLModel): icon_bg_color: Optional[str] = Field(default=None, nullable=True) data: Optional[Dict] = Field(default=None, nullable=True) is_component: Optional[bool] = Field(default=False, nullable=True) - updated_at: Optional[datetime] = Field( - default_factory=datetime.utcnow, nullable=True - ) + updated_at: Optional[datetime] = Field(default_factory=datetime.utcnow, nullable=True) folder: Optional[str] = Field(default=None, nullable=True) @field_validator("icon_bg_color") diff --git a/src/backend/langflow/services/monitor/schema.py b/src/backend/langflow/services/monitor/schema.py index dc3e2454c..c74a0fb88 100644 --- a/src/backend/langflow/services/monitor/schema.py +++ b/src/backend/langflow/services/monitor/schema.py @@ -10,9 +10,7 @@ if TYPE_CHECKING: class TransactionModel(BaseModel): id: Optional[int] = Field(default=None, alias="id") - timestamp: Optional[datetime] = Field( - default_factory=datetime.now, alias="timestamp" - ) + timestamp: Optional[datetime] = Field(default_factory=datetime.now, alias="timestamp") source: str target: str target_args: dict @@ -53,12 +51,8 @@ class MessageModel(BaseModel): @classmethod def from_record(cls, record: "Record"): # first check if the record has all the required fields - if not record.data or ( - "sender" not in record.data and "sender_name" not in record.data - ): - raise ValueError( - "The record does not have the required fields 'sender' and 'sender_name' in the data." - ) + if not record.data or ("sender" not in record.data and "sender_name" not in record.data): + raise ValueError("The record does not have the required fields 'sender' and 'sender_name' in the data.") return cls( sender=record.sender, sender_name=record.sender_name, diff --git a/src/backend/langflow/services/monitor/service.py b/src/backend/langflow/services/monitor/service.py index fdae04a4e..7a3f26517 100644 --- a/src/backend/langflow/services/monitor/service.py +++ b/src/backend/langflow/services/monitor/service.py @@ -44,9 +44,7 @@ class MonitorService(Service): def ensure_tables_exist(self): for table_name, model in self.table_map.items(): - drop_and_create_table_if_schema_mismatch( - str(self.db_path), table_name, model - ) + drop_and_create_table_if_schema_mismatch(str(self.db_path), table_name, model) def add_row( self, diff --git a/src/backend/langflow/services/task/service.py b/src/backend/langflow/services/task/service.py index 4ac6760a3..487b507cd 100644 --- a/src/backend/langflow/services/task/service.py +++ b/src/backend/langflow/services/task/service.py @@ -74,9 +74,7 @@ class TaskService(Service): result = await result return task.id, result - async def launch_task( - self, task_func: Callable[..., Any], *args: Any, **kwargs: Any - ) -> Any: + async def launch_task(self, task_func: Callable[..., Any], *args: Any, **kwargs: Any) -> Any: logger.debug(f"Launching task {task_func} with args {args} and kwargs {kwargs}") logger.debug(f"Using backend {self.backend}") task = self.backend.launch_task(task_func, *args, **kwargs) diff --git a/src/backend/langflow/template/field/base.py b/src/backend/langflow/template/field/base.py index 76e5a13d0..4cedf19f3 100644 --- a/src/backend/langflow/template/field/base.py +++ b/src/backend/langflow/template/field/base.py @@ -73,9 +73,7 @@ class TemplateField(BaseModel): refresh_button_text: Optional[str] = None """Specifies the text for the refresh button. Defaults to None.""" - range_spec: Optional[RangeSpec] = Field( - default=None, serialization_alias="rangeSpec" - ) + range_spec: Optional[RangeSpec] = Field(default=None, serialization_alias="rangeSpec") """Range specification for the field. Defaults to None.""" title_case: bool = False @@ -124,10 +122,6 @@ class TemplateField(BaseModel): if not isinstance(value, list): raise ValueError("file_types must be a list") return [ - ( - f".{file_type}" - if isinstance(file_type, str) and not file_type.startswith(".") - else file_type - ) + (f".{file_type}" if isinstance(file_type, str) and not file_type.startswith(".") else file_type) for file_type in value ] diff --git a/src/backend/langflow/utils/util.py b/src/backend/langflow/utils/util.py index 6dd931f27..7aed2018c 100644 --- a/src/backend/langflow/utils/util.py +++ b/src/backend/langflow/utils/util.py @@ -20,12 +20,8 @@ def remove_ansi_escape_codes(text): return re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", text) -def build_template_from_function( - name: str, type_to_loader_dict: Dict, add_function: bool = False -): - classes = [ - item.__annotations__["return"].__name__ for item in type_to_loader_dict.values() - ] +def build_template_from_function(name: str, type_to_loader_dict: Dict, add_function: bool = False): + classes = [item.__annotations__["return"].__name__ for item in type_to_loader_dict.values()] # Raise error if name is not in chains if name not in classes: @@ -46,10 +42,8 @@ def build_template_from_function( for name_, value_ in value.__repr_args__(): if name_ == "default_factory": try: - variables[class_field_items]["default"] = ( - get_default_factory( - module=_class.__base__.__module__, function=value_ - ) + variables[class_field_items]["default"] = get_default_factory( + module=_class.__base__.__module__, function=value_ ) except Exception: variables[class_field_items]["default"] = None @@ -57,9 +51,7 @@ def build_template_from_function( variables[class_field_items][name_] = value_ variables[class_field_items]["placeholder"] = ( - docs.params[class_field_items] - if class_field_items in docs.params - else "" + docs.params[class_field_items] if class_field_items in docs.params else "" ) # Adding function to base classes to allow # the output to be a function @@ -74,9 +66,7 @@ def build_template_from_function( } -def build_template_from_class( - name: str, type_to_cls_dict: Dict, add_function: bool = False -): +def build_template_from_class(name: str, type_to_cls_dict: Dict, add_function: bool = False): classes = [item.__name__ for item in type_to_cls_dict.values()] # Raise error if name is not in chains @@ -100,11 +90,9 @@ def build_template_from_class( for name_, value_ in value.__repr_args__(): if name_ == "default_factory": try: - variables[class_field_items]["default"] = ( - get_default_factory( - module=_class.__base__.__module__, - function=value_, - ) + variables[class_field_items]["default"] = get_default_factory( + module=_class.__base__.__module__, + function=value_, ) except Exception: variables[class_field_items]["default"] = None @@ -112,9 +100,7 @@ def build_template_from_class( variables[class_field_items][name_] = value_ variables[class_field_items]["placeholder"] = ( - docs.params[class_field_items] - if class_field_items in docs.params - else "" + docs.params[class_field_items] if class_field_items in docs.params else "" ) base_classes = get_base_classes(_class) # Adding function to base classes to allow @@ -146,9 +132,7 @@ def build_template_from_method( # Check if the method exists in this class if not hasattr(_class, method_name): - raise ValueError( - f"Method {method_name} not found in class {class_name}" - ) + raise ValueError(f"Method {method_name} not found in class {class_name}") # Get the method method = getattr(_class, method_name) @@ -167,14 +151,8 @@ def build_template_from_method( "_type": _type, **{ name: { - "default": ( - param.default if param.default != param.empty else None - ), - "type": ( - param.annotation - if param.annotation != param.empty - else None - ), + "default": (param.default if param.default != param.empty else None), + "type": (param.annotation if param.annotation != param.empty else None), "required": param.default == param.empty, } for name, param in params.items() @@ -261,9 +239,7 @@ def sync_to_async(func): return async_wrapper -def format_dict( - dictionary: Dict[str, Any], class_name: Optional[str] = None -) -> Dict[str, Any]: +def format_dict(dictionary: Dict[str, Any], class_name: Optional[str] = None) -> Dict[str, Any]: """ Formats a dictionary by removing certain keys and modifying the values of other keys. @@ -349,9 +325,7 @@ def check_list_type(_type: str, value: Dict[str, Any]) -> str: The modified type string. """ if any(list_type in _type for list_type in ["List", "Sequence", "Set"]): - _type = ( - _type.replace("List[", "").replace("Sequence[", "").replace("Set[", "")[:-1] - ) + _type = _type.replace("List[", "").replace("Sequence[", "").replace("Set[", "")[:-1] value["list"] = True else: value["list"] = False @@ -454,9 +428,7 @@ def set_headers_value(value: Dict[str, Any]) -> None: value["value"] = """{"Authorization": "Bearer "}""" -def add_options_to_field( - value: Dict[str, Any], class_name: Optional[str], key: str -) -> None: +def add_options_to_field(value: Dict[str, Any], class_name: Optional[str], key: str) -> None: """ Adds options to the field based on the class name and key. """ diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index ef191afee..397ba5b80 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -173,8 +173,9 @@ export default function GenericNode({ const iconColor = nodeColors[types[data.type]]; const iconName = iconElement || (data.node?.flow ? "group_components" : name); - const iconClassName = `generic-node-icon ${!showNode ? " absolute inset-x-6 h-12 w-12 " : "" - }`; + const iconClassName = `generic-node-icon ${ + !showNode ? " absolute inset-x-6 h-12 w-12 " : "" + }`; if (iconElement && isEmoji) { return nodeIconFragment(iconElement); } else { @@ -303,7 +304,7 @@ export default function GenericNode({ numberOfHandles={handles} showNode={showNode} openAdvancedModal={false} - onCloseAdvancedModal={() => { }} + onCloseAdvancedModal={() => {}} selected={selected} > @@ -426,33 +427,33 @@ export default function GenericNode({ data={data} color={ data.node?.template[templateField].input_types && - data.node?.template[templateField].input_types! - .length > 0 + data.node?.template[templateField].input_types! + .length > 0 ? nodeColors[ - data.node?.template[templateField] - .input_types![ - data.node?.template[templateField] - .input_types!.length - 1 - ] - ] ?? - nodeColors[ - types[ - data.node?.template[templateField] - .input_types![ - data.node?.template[templateField] - .input_types!.length - 1 - ] - ] - ] + data.node?.template[templateField] + .input_types![ + data.node?.template[templateField] + .input_types!.length - 1 + ] + ] ?? + nodeColors[ + types[ + data.node?.template[templateField] + .input_types![ + data.node?.template[templateField] + .input_types!.length - 1 + ] + ] + ] : nodeColors[ - data.node?.template[templateField].type! - ] ?? - nodeColors[ - types[ - data.node?.template[templateField].type! - ] - ] ?? - nodeColors.unknown + data.node?.template[templateField].type! + ] ?? + nodeColors[ + types[ + data.node?.template[templateField].type! + ] + ] ?? + nodeColors.unknown } title={getFieldTitle( data.node?.template!, @@ -496,7 +497,7 @@ export default function GenericNode({ color={nodeColors[types[data.type]] ?? nodeColors.unknown} title={ data.node?.output_types && - data.node.output_types.length > 0 + data.node.output_types.length > 0 ? data.node.output_types.join(" | ") : data.type } @@ -515,59 +516,62 @@ export default function GenericNode({ {showNode && ( {STATUS_BUILDING} - ) : !validationStatus ? ( - {STATUS_BUILD} - ) : ( -
-
- {lastRunTime && ( -
-
{RUN_TIMESTAMP_PREFIX}
-
- {lastRunTime} + content={ + buildStatus === BuildStatus.BUILDING ? ( + {STATUS_BUILDING} + ) : !validationStatus ? ( + {STATUS_BUILD} + ) : ( +
+
+ {lastRunTime && ( +
+
{RUN_TIMESTAMP_PREFIX}
+
+ {lastRunTime} +
+ )} +
+
+
Duration:
+
+ {validationStatus?.data.duration}
- )} -
-
-
Duration:
-
- {validationStatus?.data.duration} +
+
+ + Output + +
+ {validationString.split("\n").map((line, index) => ( +
+ {line} +
+ ))}
-
- - Output - -
- {validationString.split("\n").map((line, index) => ( -
{line}
- ))} -
-
- ) - } - side="bottom" - > - - +
+ + )}
@@ -642,7 +646,7 @@ export default function GenericNode({ }} > {(data.node?.description === "" || !data.node?.description) && - nameEditable + nameEditable ? "Double Click to Edit Description" : data.node?.description}
@@ -655,7 +659,7 @@ export default function GenericNode({ .map((templateField: string, idx) => (
{data.node!.template[templateField].show && - !data.node!.template[templateField].advanced ? ( + !data.node!.template[templateField].advanced ? ( 0 + data.node?.template[templateField].input_types! + .length > 0 ? nodeColors[ - data.node?.template[templateField].input_types![ - data.node?.template[templateField] - .input_types!.length - 1 - ] - ] ?? - nodeColors[ - types[ - data.node?.template[templateField] - .input_types![ - data.node?.template[templateField] - .input_types!.length - 1 - ] - ] - ] + data.node?.template[templateField].input_types![ + data.node?.template[templateField] + .input_types!.length - 1 + ] + ] ?? + nodeColors[ + types[ + data.node?.template[templateField] + .input_types![ + data.node?.template[templateField] + .input_types!.length - 1 + ] + ] + ] : nodeColors[ - data.node?.template[templateField].type! - ] ?? - nodeColors[ - types[data.node?.template[templateField].type!] - ] ?? - nodeColors.unknown + data.node?.template[templateField].type! + ] ?? + nodeColors[ + types[data.node?.template[templateField].type!] + ] ?? + nodeColors.unknown } title={getFieldTitle( data.node?.template!, @@ -744,9 +748,9 @@ export default function GenericNode({ data={data} color={ (data.node?.output_types && - data.node.output_types.length > 0 + data.node.output_types.length > 0 ? nodeColors[data.node.output_types[0]] ?? - nodeColors[types[data.node.output_types[0]]] + nodeColors[types[data.node.output_types[0]]] : nodeColors[types[data.type]]) ?? nodeColors.unknown } title={ diff --git a/src/frontend/src/components/IOview/index.tsx b/src/frontend/src/components/IOview/index.tsx index 805e87318..3af96dc51 100644 --- a/src/frontend/src/components/IOview/index.tsx +++ b/src/frontend/src/components/IOview/index.tsx @@ -20,7 +20,12 @@ import { Badge } from "../ui/badge"; import { Button } from "../ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"; -export default function IOView({ children, open, setOpen, disable }: { +export default function IOView({ + children, + open, + setOpen, + disable, +}: { children: JSX.Element; open: boolean; setOpen: (open: boolean) => void; diff --git a/src/frontend/src/components/NewFLowCard2/index.tsx b/src/frontend/src/components/NewFLowCard2/index.tsx index fe63413e2..7f364cfef 100644 --- a/src/frontend/src/components/NewFLowCard2/index.tsx +++ b/src/frontend/src/components/NewFLowCard2/index.tsx @@ -1,26 +1,25 @@ -import { Card, CardContent, CardDescription, CardTitle } from "../ui/card"; -import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { useNavigate } from "react-router-dom"; -import IconComponent from "../genericIconComponent"; -import { cn } from "../../utils/utils"; +import useFlowsManagerStore from "../../stores/flowsManagerStore"; +import { Card, CardContent, CardDescription, CardTitle } from "../ui/card"; export default function NewFlowCardComponent() { - const addFlow = useFlowsManagerStore((state) => state.addFlow); - const navigate = useNavigate(); - return ( - { - addFlow(true).then((id) => { - navigate("/flow/" + id); - }); - }} className="pt-4 w-80 h-64 cursor-pointer bg-background"> - -
- -
-
- - Blank Flow - -
- ) -} \ No newline at end of file + const addFlow = useFlowsManagerStore((state) => state.addFlow); + const navigate = useNavigate(); + return ( + { + addFlow(true).then((id) => { + navigate("/flow/" + id); + }); + }} + className="h-64 w-80 cursor-pointer bg-background pt-4" + > + +
+
+ + Blank Flow + +
+ ); +} diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 3d3a01562..9847fd1e6 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -1,16 +1,15 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import useFlowStore from "../../stores/flowStore"; -import { ChatType } from "../../types/chat"; -import IOView from "../IOview"; -import ChatTrigger from "../ViewTriggers/chat"; import { Transition } from "@headlessui/react"; +import { useEffect, useMemo, useRef, useState } from "react"; +import ApiModal from "../../modals/ApiModal"; +import ShareModal from "../../modals/shareModal"; +import useFlowStore from "../../stores/flowStore"; +import useFlowsManagerStore from "../../stores/flowsManagerStore"; +import { useStoreStore } from "../../stores/storeStore"; +import { ChatType } from "../../types/chat"; +import { classNames } from "../../utils/utils"; +import IOView from "../IOview"; import ForwardedIconComponent from "../genericIconComponent"; import { Separator } from "../ui/separator"; -import ShareModal from "../../modals/shareModal"; -import { useStoreStore } from "../../stores/storeStore"; -import useFlowsManagerStore from "../../stores/flowsManagerStore"; -import { classNames } from "../../utils/utils"; -import ApiModal from "../../modals/ApiModal"; export default function FlowToolbar({ flow }: ChatType): JSX.Element { const [open, setOpen] = useState(false); @@ -51,7 +50,7 @@ export default function FlowToolbar({ flow }: ChatType): JSX.Element {
-
+
Legacy Components
diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 637779cc1..39f5f6660 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -13,6 +13,7 @@ import { import ConfirmationModal from "../../../../modals/ConfirmationModal"; import EditNodeModal from "../../../../modals/EditNodeModal"; import ShareModal from "../../../../modals/shareModal"; +import useAlertStore from "../../../../stores/alertStore"; import { useDarkStore } from "../../../../stores/darkStore"; import useFlowStore from "../../../../stores/flowStore"; import useFlowsManagerStore from "../../../../stores/flowsManagerStore"; @@ -27,7 +28,6 @@ import { updateFlowPosition, } from "../../../../utils/reactflowUtils"; import { classNames, cn } from "../../../../utils/utils"; -import useAlertStore from "../../../../stores/alertStore"; export default function NodeToolbarComponent({ data, @@ -97,8 +97,8 @@ export default function NodeToolbarComponent({ (state) => state.setLastCopiedSelection ); - const setSuccessData = useAlertStore(state => state.setSuccessData); - const setNoticeData = useAlertStore(state => state.setNoticeData); + const setSuccessData = useAlertStore((state) => state.setSuccessData); + const setNoticeData = useAlertStore((state) => state.setNoticeData); useEffect(() => { setFlowComponent(createFlowComponent(cloneDeep(data), version)); @@ -166,10 +166,8 @@ export default function NodeToolbarComponent({ { x: 50, y: 10, - paneX: nodes.find((node) => node.id === data.id)?.position - .x, - paneY: nodes.find((node) => node.id === data.id)?.position - .y, + paneX: nodes.find((node) => node.id === data.id)?.position.x, + paneY: nodes.find((node) => node.id === data.id)?.position.y, } ); break; @@ -229,7 +227,7 @@ export default function NodeToolbarComponent({ const [openModal, setOpenModal] = useState(false); const hasCode = Object.keys(data.node!.template).includes("code"); - + useEffect(() => { function onKeyDown(event: KeyboardEvent) { if ( @@ -260,18 +258,17 @@ export default function NodeToolbarComponent({ event.preventDefault(); setShowconfirmShare((state) => !state); } - if ( - selected && - (event.ctrlKey || event.metaKey) && - event.key === "q" - ) { + if (selected && (event.ctrlKey || event.metaKey) && event.key === "q") { event.preventDefault(); if (isMinimal) { - setShowState(show => !show) + setShowState((show) => !show); setShowNode(data.showNode ?? true ? false : true); - return + return; } - setNoticeData({title: "Minimization are only available for nodes with one handle or fewer."}); + setNoticeData({ + title: + "Minimization are only available for nodes with one handle or fewer.", + }); } if ( selected && @@ -281,7 +278,7 @@ export default function NodeToolbarComponent({ ) { event.preventDefault(); if (hasCode) return setOpenModal((state) => !state); - setNoticeData({title: `You can not access ${data.id} code`}) + setNoticeData({ title: `You can not access ${data.id} code` }); } if ( selected && @@ -292,11 +289,7 @@ export default function NodeToolbarComponent({ event.preventDefault(); setShowModalAdvanced((state) => !state); } - if ( - selected && - (event.ctrlKey || event.metaKey) && - event.key === "s" - ) { + if (selected && (event.ctrlKey || event.metaKey) && event.key === "s") { if (isSaved) { event.preventDefault(); return setShowOverrideModal((state) => !state); @@ -304,7 +297,7 @@ export default function NodeToolbarComponent({ if (hasCode) { event.preventDefault(); saveComponent(cloneDeep(data), false); - setSuccessData({title: `${data.id} saved successfully`}) + setSuccessData({ title: `${data.id} saved successfully` }); } } if ( @@ -317,7 +310,9 @@ export default function NodeToolbarComponent({ if (data.node?.documentation) { return openInNewTab(data.node?.documentation); } - setNoticeData({title: `${data.id} docs is not available at the moment.`}) + setNoticeData({ + title: `${data.id} docs is not available at the moment.`, + }); } } @@ -349,7 +344,8 @@ export default function NodeToolbarComponent({ @@ -425,28 +418,35 @@ export default function NodeToolbarComponent({ Edit{" "} {navigator.userAgent.toUpperCase().includes("MAC") ? ( + name="Command" + className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" + > ) : ( - Ctrl + + + Ctrl +{" "} + )} E
- )} + )}
- + Duplicate {navigator.userAgent.toUpperCase().includes("MAC") ? ( - - ) : ( - Ctrl + - )} + ) : ( + + Ctrl +{" "} + + )} D
{" "}
@@ -458,13 +458,15 @@ export default function NodeToolbarComponent({ />{" "} Copy{" "} {navigator.userAgent.toUpperCase().includes("MAC") ? ( - - ) : ( - Ctrl + - )} + ) : ( + + Ctrl +{" "} + + )} C @@ -481,13 +483,14 @@ export default function NodeToolbarComponent({ Share{" "} {navigator.userAgent.toUpperCase().includes("MAC") ? ( + name="Command" + className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" + > ) : ( - Ctrl + + Ctrl + )} - {" "} Docs{" "} {navigator.userAgent.toUpperCase().includes("MAC") ? ( - - ) : ( - Ctrl - )} + ) : ( + + Ctrl + + )} + name="Command" + className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" + > ) : ( - Ctrl + + + Ctrl +{" "} + )} Q @@ -562,11 +569,13 @@ export default function NodeToolbarComponent({ Ungroup{" "} {navigator.userAgent.toUpperCase().includes("MAC") ? ( + name="Command" + className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" + > ) : ( - Ctrl + + + Ctrl +{" "} + )} U @@ -601,12 +610,12 @@ export default function NodeToolbarComponent({ index={6} onConfirm={(index, user) => { saveComponent(cloneDeep(data), true); - setSuccessData({title: `${data.id} successfully overridden!`}) + setSuccessData({ title: `${data.id} successfully overridden!` }); }} onClose={setShowOverrideModal} onCancel={() => { - saveComponent(cloneDeep(data), false) - setSuccessData({title: "New node successfully saved!"}) + saveComponent(cloneDeep(data), false); + setSuccessData({ title: "New node successfully saved!" }); }} > diff --git a/src/frontend/src/pages/MainPage/index.tsx b/src/frontend/src/pages/MainPage/index.tsx index 65c5b7f09..b4535a526 100644 --- a/src/frontend/src/pages/MainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/index.tsx @@ -2,15 +2,14 @@ import { Group, ToyBrick } from "lucide-react"; import { useEffect, useState } from "react"; import { Outlet, useLocation, useNavigate } from "react-router-dom"; import DropdownButton from "../../components/DropdownButtonComponent"; -import NewFlowCardComponent from "../../components/NewFLowCard2";; -import ExampleCardComponent from "../../components/exampleComponent"; +import NewFlowCardComponent from "../../components/NewFLowCard2"; import IconComponent from "../../components/genericIconComponent"; import PageLayout from "../../components/pageLayout"; import SidebarNav from "../../components/sidebarComponent"; import { Button } from "../../components/ui/button"; +import UndrawCardComponent from "../../components/undrawCards"; import { CONSOLE_ERROR_MSG } from "../../constants/alerts_constants"; import { - EXAMPLES_MOCK, MY_COLLECTION_DESC, USER_PROJECTS_HEADER, } from "../../constants/constants"; @@ -18,7 +17,6 @@ import BaseModal from "../../modals/baseModal"; import useAlertStore from "../../stores/alertStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { downloadFlows } from "../../utils/reactflowUtils"; -import UndrawCardComponent from "../../components/undrawCards"; export default function HomePage(): JSX.Element { const addFlow = useFlowsManagerStore((state) => state.addFlow); const uploadFlow = useFlowsManagerStore((state) => state.uploadFlow); @@ -120,9 +118,7 @@ export default function HomePage(): JSX.Element { - + Get Started @@ -133,7 +129,7 @@ export default function HomePage(): JSX.Element { /> */} -
+
{examples.map((example, idx) => { return ; })} diff --git a/src/frontend/tailwind.config.js b/src/frontend/tailwind.config.js index 1dbe0b02d..20ee851ff 100644 --- a/src/frontend/tailwind.config.js +++ b/src/frontend/tailwind.config.js @@ -87,7 +87,7 @@ module.exports = { "beta-foreground": "var(--beta-foreground)", "chat-bot-icon": "var(--chat-bot-icon)", "chat-user-icon": "var(--chat-user-icon)", - "ice": "var(--ice)", + ice: "var(--ice)", hover: "var(--hover)", white: "var(--white)", border: "hsl(var(--border))", @@ -224,6 +224,6 @@ module.exports = { }), require("@tailwindcss/typography"), require("daisyui"), - require('tailwindcss-dotted-background'), + require("tailwindcss-dotted-background"), ], }; diff --git a/tests/test_api_key.py b/tests/test_api_key.py index 7988793d4..31f484d60 100644 --- a/tests/test_api_key.py +++ b/tests/test_api_key.py @@ -1,4 +1,5 @@ import pytest + from langflow.services.database.models.api_key import ApiKeyCreate @@ -21,7 +22,6 @@ def test_get_api_keys(client, logged_in_headers, api_key): assert any("test-api-key" in api_key["name"] for api_key in data["api_keys"]) # assert all api keys in data["api_keys"] are masked assert all("**" in api_key["api_key"] for api_key in data["api_keys"]) - # Add more assertions as needed based on the expected data structure and content def test_create_api_key(client, logged_in_headers): diff --git a/tests/test_initial_setup.py b/tests/test_initial_setup.py index 9b34f844d..d60d4951a 100644 --- a/tests/test_initial_setup.py +++ b/tests/test_initial_setup.py @@ -38,9 +38,7 @@ def test_create_or_update_starter_projects(client): num_projects = len(load_starter_projects()) # Get the number of projects in the database - num_db_projects = session.exec( - select(func.count(Flow.id)).where(Flow.folder == STARTER_FOLDER_NAME) - ).one() + num_db_projects = session.exec(select(func.count(Flow.id)).where(Flow.folder == STARTER_FOLDER_NAME)).one() # Check that the number of projects in the database is the same as the number of projects returned by load_starter_projects assert num_db_projects == num_projects @@ -56,21 +54,16 @@ async def test_starter_project_can_run_successfully(client): num_projects = len(load_starter_projects()) # Get the number of projects in the database - num_db_projects = session.exec( - select(func.count(Flow.id)).where(Flow.folder == STARTER_FOLDER_NAME) - ).one() + num_db_projects = session.exec(select(func.count(Flow.id)).where(Flow.folder == STARTER_FOLDER_NAME)).one() # Check that the number of projects in the database is the same as the number of projects returned by load_starter_projects assert num_db_projects == num_projects # Get all the starter projects - projects = session.exec( - select(Flow).where(Flow.folder == STARTER_FOLDER_NAME) - ).all() + projects = session.exec(select(Flow).where(Flow.folder == STARTER_FOLDER_NAME)).all() graphs: list[Graph] = [ - (project.name, Graph.from_payload(project.data, flow_id=project.id)) - for project in projects + (project.name, Graph.from_payload(project.data, flow_id=project.id)) for project in projects ] assert len(graphs) == len(projects) for name, graph in graphs: diff --git a/tests/test_process.py b/tests/test_process.py index 28de99331..1b75f9406 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -268,13 +268,9 @@ async def test_load_langchain_object_with_cached_session(client, basic_graph_dat # Provide a non-existent session_id session_service = get_session_service() session_id1 = "non-existent-session-id" - graph1, artifacts1 = await session_service.load_session( - session_id1, basic_graph_data - ) + graph1, artifacts1 = await session_service.load_session(session_id1, basic_graph_data) # Use the new session_id to get the langchain_object again - graph2, artifacts2 = await session_service.load_session( - session_id1, basic_graph_data - ) + graph2, artifacts2 = await session_service.load_session(session_id1, basic_graph_data) assert graph1 == graph2 assert artifacts1 == artifacts2 @@ -286,15 +282,11 @@ async def test_load_langchain_object_with_no_cached_session(client, basic_graph_ session_service = get_session_service() session_id1 = "non-existent-session-id" session_id = session_service.build_key(session_id1, basic_graph_data) - graph1, artifacts1 = await session_service.load_session( - session_id, basic_graph_data - ) + graph1, artifacts1 = await session_service.load_session(session_id, basic_graph_data) # Clear the cache session_service.clear_session(session_id) # Use the new session_id to get the langchain_object again - graph2, artifacts2 = await session_service.load_session( - session_id, basic_graph_data - ) + graph2, artifacts2 = await session_service.load_session(session_id, basic_graph_data) assert id(graph1) != id(graph2) # Since the cache was cleared, objects should be different @@ -305,12 +297,8 @@ async def test_load_langchain_object_without_session_id(client, basic_graph_data # Provide a non-existent session_id session_service = get_session_service() session_id1 = None - graph1, artifacts1 = await session_service.load_session( - session_id1, basic_graph_data - ) + graph1, artifacts1 = await session_service.load_session(session_id1, basic_graph_data) # Use the new session_id to get the langchain_object again - graph2, artifacts2 = await session_service.load_session( - session_id1, basic_graph_data - ) + graph2, artifacts2 = await session_service.load_session(session_id1, basic_graph_data) assert graph1 == graph2