Fix bug in login functionality

This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-11-21 14:13:51 -03:00
commit 777686dd65

View file

@ -1,43 +1,39 @@
import ast import ast
import contextlib 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 uuid import UUID
from fastapi import HTTPException
from langflow.api.utils import get_new_key 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.agents.base import agent_creator
from langflow.interface.chains.base import chain_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.custom.utils import extract_inner_type
from langflow.interface.document_loaders.base import documentloader_creator from langflow.interface.document_loaders.base import documentloader_creator
from langflow.interface.embeddings.base import embedding_creator from langflow.interface.embeddings.base import embedding_creator
from langflow.interface.importing.utils import get_function_custom from langflow.interface.importing.utils import get_function_custom
from langflow.interface.llms.base import llm_creator from langflow.interface.llms.base import llm_creator
from langflow.interface.memories.base import memory_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.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.text_splitters.base import textsplitter_creator
from langflow.interface.toolkits.base import toolkits_creator from langflow.interface.toolkits.base import toolkits_creator
from langflow.interface.tools.base import tool_creator from langflow.interface.tools.base import tool_creator
from langflow.interface.utilities.base import utility_creator from langflow.interface.utilities.base import utility_creator
from langflow.interface.vector_store.base import vectorstore_creator from langflow.interface.vector_store.base import vectorstore_creator
from langflow.interface.wrappers.base import wrapper_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.field.base import TemplateField
from langflow.template.frontend_node.constants import CLASSES_TO_REMOVE from langflow.template.frontend_node.constants import CLASSES_TO_REMOVE
from langflow.template.frontend_node.custom_components import ( from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode
CustomComponentFrontendNode,
)
from langflow.interface.retrievers.base import retriever_creator
from langflow.interface.custom.directory_reader import DirectoryReader
from loguru import logger
from langflow.utils.util import get_base_classes from langflow.utils.util import get_base_classes
from loguru import logger
import re
import warnings
import traceback
from fastapi import HTTPException
# Used to get the base_classes list # 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 a list, then it's a dropdown
# If options is None, then it's a list of strings # If options is None, then it's a list of strings
is_list = isinstance(field_config.get("options"), list) is_list = isinstance(field_config.get("options"), list)
field_config["is_list"] = ( field_config["is_list"] = is_list or field_config.get("is_list", False) or field_contains_list
is_list or field_config.get("is_list", False) or field_contains_list
)
if "name" in field_config: if "name" in field_config:
warnings.warn( warnings.warn("The 'name' key in field_config is used to build the object and can't be changed.")
"The 'name' key in field_config is used to build the object and can't be changed."
)
field_config.pop("name", None) field_config.pop("name", None)
required = field_config.pop("required", field_required) 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): def build_frontend_node(custom_component: CustomComponent):
"""Build a frontend node for a custom component""" """Build a frontend node for a custom component"""
try: try:
return ( return CustomComponentFrontendNode().to_dict().get(type(custom_component).__name__)
CustomComponentFrontendNode().to_dict().get(type(custom_component).__name__)
)
except Exception as exc: except Exception as exc:
logger.error(f"Error while building base frontend node: {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( 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""" """Build the field configuration for a custom component"""
@ -221,7 +211,37 @@ def build_field_config(
return {} return {}
try: 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: except Exception as exc:
logger.error(f"Error while building field config: {str(exc)}") logger.error(f"Error while building field config: {str(exc)}")
return {} 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": if "name" not in extra_field or extra_field["name"] == "self":
continue continue
field_name, field_type, field_value, field_required = get_field_properties( field_name, field_type, field_value, field_required = get_field_properties(extra_field)
extra_field
)
config = field_config.get(field_name, {}) config = field_config.get(field_name, {})
frontend_node = add_new_custom_field( frontend_node = add_new_custom_field(
frontend_node, frontend_node,
@ -276,8 +294,7 @@ def add_base_classes(frontend_node, return_types: List[str]):
status_code=400, status_code=400,
detail={ detail={
"error": ( "error": (
"Invalid return type should be one of: " "Invalid return type should be one of: " f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}"
f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}"
), ),
"traceback": traceback.format_exc(), "traceback": traceback.format_exc(),
}, },
@ -299,8 +316,7 @@ def add_output_types(frontend_node, return_types: List[str]):
status_code=400, status_code=400,
detail={ detail={
"error": ( "error": (
"Invalid return type should be one of: " "Invalid return type should be one of: " f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}"
f"{list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())}"
), ),
"traceback": traceback.format_exc(), "traceback": traceback.format_exc(),
}, },
@ -310,7 +326,9 @@ def add_output_types(frontend_node, return_types: List[str]):
def build_langchain_template_custom_component( 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""" """Build a custom component template for the langchain"""
try: try:
@ -330,16 +348,10 @@ def build_langchain_template_custom_component(
add_extra_fields(frontend_node, field_config, entrypoint_args) add_extra_fields(frontend_node, field_config, entrypoint_args)
logger.debug("Added extra fields") logger.debug("Added extra fields")
frontend_node = add_code_field( frontend_node = add_code_field(frontend_node, custom_component.code, field_config.get("code", {}))
frontend_node, custom_component.code, field_config.get("code", {})
)
logger.debug("Added code field") logger.debug("Added code field")
add_base_classes( add_base_classes(frontend_node, custom_component.get_function_entrypoint_return_type)
frontend_node, custom_component.get_function_entrypoint_return_type add_output_types(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") logger.debug("Added base classes")
return frontend_node return frontend_node
except Exception as exc: except Exception as exc:
@ -348,9 +360,7 @@ def build_langchain_template_custom_component(
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,
detail={ detail={
"error": ( "error": ("Invalid type convertion. Please check your code and try again."),
"Invalid type convertion. Please check your code and try again."
),
"traceback": traceback.format_exc(), "traceback": traceback.format_exc(),
}, },
) from exc ) from exc
@ -382,9 +392,7 @@ def build_valid_menu(valid_components):
valid_menu[menu_name] = {} valid_menu[menu_name] = {}
for component in menu_item["components"]: for component in menu_item["components"]:
logger.debug( logger.debug(f"Building component: {component.get('name'), component.get('output_types')}")
f"Building component: {component.get('name'), component.get('output_types')}"
)
try: try:
component_name = component["name"] component_name = component["name"]
component_code = component["code"] component_code = component["code"]
@ -393,9 +401,7 @@ def build_valid_menu(valid_components):
component_extractor = CustomComponent(code=component_code) component_extractor = CustomComponent(code=component_code)
component_extractor.is_check_valid() component_extractor.is_check_valid()
component_template = build_langchain_template_custom_component( component_template = build_langchain_template_custom_component(component_extractor)
component_extractor
)
component_template["output_types"] = component_output_types component_template["output_types"] = component_output_types
if len(component_output_types) == 1: if len(component_output_types) == 1:
component_name = component_output_types[0] component_name = component_output_types[0]
@ -403,9 +409,7 @@ def build_valid_menu(valid_components):
file_name = component.get("file").split(".")[0] file_name = component.get("file").split(".")[0]
if "_" in file_name: if "_" in file_name:
# turn .py file into camelcase # turn .py file into camelcase
component_name = "".join( component_name = "".join([word.capitalize() for word in file_name.split("_")])
[word.capitalize() for word in file_name.split("_")]
)
else: else:
component_name = file_name component_name = file_name
@ -414,9 +418,7 @@ def build_valid_menu(valid_components):
except Exception as exc: except Exception as exc:
logger.error(f"Error loading Component: {component['output_types']}") logger.error(f"Error loading Component: {component['output_types']}")
logger.exception( logger.exception(f"Error while building custom component {component_output_types}: {exc}")
f"Error while building custom component {component_output_types}: {exc}"
)
return valid_menu 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}") logger.debug(f"Added {component_name} to invalid menu to {menu_name}")
except Exception as exc: except Exception as exc:
logger.exception( logger.exception(f"Error while creating custom component [{component_name}]: {str(exc)}")
f"Error while creating custom component [{component_name}]: {str(exc)}"
)
return invalid_menu return invalid_menu
def merge_nested_dicts_with_renaming(dict1, dict2): def merge_nested_dicts_with_renaming(dict1, dict2):
for key, value in dict2.items(): for key, value in dict2.items():
if ( if key in dict1 and isinstance(value, dict) and isinstance(dict1.get(key), dict):
key in dict1
and isinstance(value, dict)
and isinstance(dict1.get(key), dict)
):
for sub_key, sub_value in value.items(): for sub_key, sub_value in value.items():
if sub_key in dict1[key]: if sub_key in dict1[key]:
new_key = get_new_key(dict1[key], sub_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) file_list = load_files_from_path(path)
reader = DirectoryReader(path, False) reader = DirectoryReader(path, False)
valid_components, invalid_components = build_and_validate_all_files( valid_components, invalid_components = build_and_validate_all_files(reader, file_list)
reader, file_list
)
valid_menu = build_valid_menu(valid_components) valid_menu = build_valid_menu(valid_components)
invalid_menu = build_invalid_menu(invalid_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 # need to merge all the keys into one dict
custom_components_from_file: dict[str, Any] = {} custom_components_from_file: dict[str, Any] = {}
if settings_service.settings.COMPONENTS_PATH: if settings_service.settings.COMPONENTS_PATH:
logger.info( logger.info(f"Building custom components from {settings_service.settings.COMPONENTS_PATH}")
f"Building custom components from {settings_service.settings.COMPONENTS_PATH}"
)
custom_component_dicts = [] custom_component_dicts = []
processed_paths = [] processed_paths = []
for path in settings_service.settings.COMPONENTS_PATH: for path in settings_service.settings.COMPONENTS_PATH:
if str(path) in processed_paths: if str(path) in processed_paths:
continue continue
custom_component_dict = build_langchain_custom_component_list_from_path( custom_component_dict = build_langchain_custom_component_list_from_path(str(path))
str(path)
)
custom_component_dicts.append(custom_component_dict) custom_component_dicts.append(custom_component_dict)
processed_paths.append(str(path)) processed_paths.append(str(path))
@ -521,16 +511,12 @@ def get_all_types_dict(settings_service):
if not custom_component_dict: if not custom_component_dict:
continue continue
category = list(custom_component_dict.keys())[0] category = list(custom_component_dict.keys())[0]
logger.info( logger.info(f"Loading {len(custom_component_dict[category])} component(s) from category {category}")
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 = merge_nested_dicts_with_renaming(
custom_components_from_file, custom_component_dict custom_components_from_file, custom_component_dict
) )
return merge_nested_dicts_with_renaming( return merge_nested_dicts_with_renaming(native_components, custom_components_from_file)
native_components, custom_components_from_file
)
def merge_nested_dicts(dict1, dict2): def merge_nested_dicts(dict1, dict2):