From 777686dd65f2a24675b12503b615ecb1a4950d85 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 21 Nov 2023 14:13:51 -0300 Subject: [PATCH] Fix bug in login functionality --- src/backend/langflow/interface/types.py | 154 +++++++++++------------- 1 file changed, 70 insertions(+), 84 deletions(-) diff --git a/src/backend/langflow/interface/types.py b/src/backend/langflow/interface/types.py index e48255de9..3172eacec 100644 --- a/src/backend/langflow/interface/types.py +++ b/src/backend/langflow/interface/types.py @@ -1,43 +1,39 @@ import ast import contextlib -from typing import Any, List, Union, Optional +import re +import traceback +import warnings +from typing import Any, Dict, List, Optional, Union from uuid import UUID + +from fastapi import HTTPException from langflow.api.utils import get_new_key +from langflow.field_typing.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES from langflow.interface.agents.base import agent_creator from langflow.interface.chains.base import chain_creator -from langflow.field_typing.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES +from langflow.interface.custom.base import custom_component_creator +from langflow.interface.custom.custom_component import CustomComponent +from langflow.interface.custom.directory_reader import DirectoryReader from langflow.interface.custom.utils import extract_inner_type from langflow.interface.document_loaders.base import documentloader_creator from langflow.interface.embeddings.base import embedding_creator from langflow.interface.importing.utils import get_function_custom from langflow.interface.llms.base import llm_creator from langflow.interface.memories.base import memory_creator +from langflow.interface.output_parsers.base import output_parser_creator from langflow.interface.prompts.base import prompt_creator +from langflow.interface.retrievers.base import retriever_creator from langflow.interface.text_splitters.base import textsplitter_creator from langflow.interface.toolkits.base import toolkits_creator from langflow.interface.tools.base import tool_creator from langflow.interface.utilities.base import utility_creator from langflow.interface.vector_store.base import vectorstore_creator from langflow.interface.wrappers.base import wrapper_creator -from langflow.interface.output_parsers.base import output_parser_creator -from langflow.interface.custom.base import custom_component_creator -from langflow.interface.custom.custom_component import CustomComponent - from langflow.template.field.base import TemplateField from langflow.template.frontend_node.constants import CLASSES_TO_REMOVE -from langflow.template.frontend_node.custom_components import ( - CustomComponentFrontendNode, -) -from langflow.interface.retrievers.base import retriever_creator - -from langflow.interface.custom.directory_reader import DirectoryReader -from loguru import logger +from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode from langflow.utils.util import get_base_classes - -import re -import warnings -import traceback -from fastapi import HTTPException +from loguru import logger # Used to get the base_classes list @@ -115,14 +111,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("is_list", False) or field_contains_list - ) + field_config["is_list"] = is_list or field_config.get("is_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.") field_config.pop("name", None) required = field_config.pop("required", field_required) @@ -186,9 +178,7 @@ def extract_type_from_optional(field_type): def build_frontend_node(custom_component: CustomComponent): """Build a frontend node for a custom component""" try: - return ( - CustomComponentFrontendNode().to_dict().get(type(custom_component).__name__) - ) + return CustomComponentFrontendNode().to_dict().get(type(custom_component).__name__) except Exception as exc: logger.error(f"Error while building base frontend node: {exc}") @@ -210,7 +200,7 @@ def update_attributes(frontend_node, template_config): def build_field_config( - custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None + custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None, update_field=None ): """Build the field configuration for a custom component""" @@ -221,7 +211,37 @@ def build_field_config( return {} try: - return custom_class(user_id=user_id).build_config() + build_config: Dict = custom_class(user_id=user_id).build_config() + + if update_field is not None: + try: + field_dict = build_config[update_field] + # If "options" in field_dict, and it is a callable + # then call it to get the options + if "options" in field_dict and callable(field_dict["options"]): + field_dict["options"] = field_dict["options"]() + elif "value" in field_dict and callable(field_dict["value"]): + field_dict["value"] = field_dict["value"]() + # Now we need to update the build_config + # with the new field_dict + build_config[update_field] = field_dict + except Exception as exc: + logger.error(f"Error while getting build_config: {str(exc)}") + else: + # Update all the fields + for field_name, field_dict in build_config.items(): + # If "options" in field_dict, and it is a callable + # then call it to get the options + if "options" in field_dict and callable(field_dict["options"]): + field_dict["options"] = field_dict["options"]() + elif "value" in field_dict and callable(field_dict["value"]): + field_dict["value"] = field_dict["value"]() + # Now we need to update the build_config + # with the new field_dict + build_config[field_name] = field_dict + + return build_config + except Exception as exc: logger.error(f"Error while building field config: {str(exc)}") return {} @@ -239,9 +259,7 @@ def add_extra_fields(frontend_node, field_config, function_args): if "name" not in extra_field or extra_field["name"] == "self": 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.get(field_name, {}) frontend_node = add_new_custom_field( frontend_node, @@ -276,8 +294,7 @@ def add_base_classes(frontend_node, return_types: List[str]): status_code=400, detail={ "error": ( - "Invalid return type should be one of: " - f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}" + "Invalid return type should be one of: " f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}" ), "traceback": traceback.format_exc(), }, @@ -299,8 +316,7 @@ def add_output_types(frontend_node, return_types: List[str]): status_code=400, detail={ "error": ( - "Invalid return type should be one of: " - f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}" + "Invalid return type should be one of: " f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}" ), "traceback": traceback.format_exc(), }, @@ -310,7 +326,9 @@ def add_output_types(frontend_node, return_types: List[str]): def build_langchain_template_custom_component( - custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None + custom_component: CustomComponent, + user_id: Optional[Union[str, UUID]] = None, + update_field: Optional[str] = None, ): """Build a custom component template for the langchain""" try: @@ -330,16 +348,10 @@ def build_langchain_template_custom_component( add_extra_fields(frontend_node, field_config, entrypoint_args) logger.debug("Added extra fields") - 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", {})) logger.debug("Added code field") - 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) logger.debug("Added base classes") return frontend_node except Exception as exc: @@ -348,9 +360,7 @@ def build_langchain_template_custom_component( 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 @@ -382,9 +392,7 @@ def build_valid_menu(valid_components): valid_menu[menu_name] = {} for component in menu_item["components"]: - logger.debug( - f"Building component: {component.get('name'), component.get('output_types')}" - ) + logger.debug(f"Building component: {component.get('name'), component.get('output_types')}") try: component_name = component["name"] component_code = component["code"] @@ -393,9 +401,7 @@ def build_valid_menu(valid_components): component_extractor = CustomComponent(code=component_code) component_extractor.is_check_valid() - component_template = build_langchain_template_custom_component( - component_extractor - ) + component_template = build_langchain_template_custom_component(component_extractor) component_template["output_types"] = component_output_types if len(component_output_types) == 1: component_name = component_output_types[0] @@ -403,9 +409,7 @@ def build_valid_menu(valid_components): file_name = component.get("file").split(".")[0] if "_" in file_name: # turn .py file into camelcase - component_name = "".join( - [word.capitalize() for word in file_name.split("_")] - ) + component_name = "".join([word.capitalize() for word in file_name.split("_")]) else: component_name = file_name @@ -414,9 +418,7 @@ def build_valid_menu(valid_components): except Exception as exc: logger.error(f"Error loading Component: {component['output_types']}") - logger.exception( - f"Error while building custom component {component_output_types}: {exc}" - ) + logger.exception(f"Error while building custom component {component_output_types}: {exc}") return valid_menu @@ -454,20 +456,14 @@ def build_invalid_menu(invalid_components): logger.debug(f"Added {component_name} to invalid menu to {menu_name}") except Exception as exc: - logger.exception( - f"Error while creating custom component [{component_name}]: {str(exc)}" - ) + logger.exception(f"Error while creating custom component [{component_name}]: {str(exc)}") return invalid_menu def merge_nested_dicts_with_renaming(dict1, dict2): for key, value in dict2.items(): - if ( - key in dict1 - and isinstance(value, dict) - and isinstance(dict1.get(key), dict) - ): + if key in dict1 and isinstance(value, dict) and isinstance(dict1.get(key), dict): for sub_key, sub_value in value.items(): if sub_key in dict1[key]: new_key = get_new_key(dict1[key], sub_key) @@ -484,9 +480,7 @@ def build_langchain_custom_component_list_from_path(path: str): file_list = load_files_from_path(path) reader = DirectoryReader(path, False) - valid_components, invalid_components = build_and_validate_all_files( - reader, file_list - ) + valid_components, invalid_components = build_and_validate_all_files(reader, file_list) valid_menu = build_valid_menu(valid_components) invalid_menu = build_invalid_menu(invalid_components) @@ -500,18 +494,14 @@ def get_all_types_dict(settings_service): # need to merge all the keys into one dict custom_components_from_file: dict[str, Any] = {} if settings_service.settings.COMPONENTS_PATH: - logger.info( - f"Building custom components from {settings_service.settings.COMPONENTS_PATH}" - ) + logger.info(f"Building custom components from {settings_service.settings.COMPONENTS_PATH}") custom_component_dicts = [] processed_paths = [] for path in settings_service.settings.COMPONENTS_PATH: if str(path) in processed_paths: continue - custom_component_dict = build_langchain_custom_component_list_from_path( - str(path) - ) + custom_component_dict = build_langchain_custom_component_list_from_path(str(path)) custom_component_dicts.append(custom_component_dict) processed_paths.append(str(path)) @@ -521,16 +511,12 @@ def get_all_types_dict(settings_service): if not custom_component_dict: continue category = list(custom_component_dict.keys())[0] - 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 ) - return merge_nested_dicts_with_renaming( - native_components, custom_components_from_file - ) + return merge_nested_dicts_with_renaming(native_components, custom_components_from_file) def merge_nested_dicts(dict1, dict2):