diff --git a/src/backend/langflow/interface/utilities/base.py b/src/backend/langflow/interface/utilities/base.py index e60e344ad..3a8473eee 100644 --- a/src/backend/langflow/interface/utilities/base.py +++ b/src/backend/langflow/interface/utilities/base.py @@ -1,26 +1,53 @@ -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Type from langflow.custom.customs import get_custom_nodes from langflow.interface.base import LangChainTypeCreator from langflow.interface.custom_lists import utility_type_to_cls_dict +from langflow.interface.importing.utils import import_class from langflow.settings import settings +from langflow.template.frontend_node.utilities import UtilitiesFrontendNode from langflow.utils.logger import logger from langflow.utils.util import build_template_from_class +from langchain import utilities, SQLDatabase + class UtilityCreator(LangChainTypeCreator): type_name: str = "utilities" + @property + def frontend_node_class(self) -> Type[UtilitiesFrontendNode]: + return UtilitiesFrontendNode + @property def type_to_loader_dict(self) -> Dict: - return utility_type_to_cls_dict + """ + Returns a dictionary mapping utility names to their corresponding loader classes. + If the dictionary has not been created yet, it is created by importing all utility classes + from the langchain.chains module and filtering them according to the settings.utilities list. + """ + if self.type_dict is None: + self.type_dict = { + utility_name: import_class(f"langchain.utilities.{utility_name}") + for utility_name in utilities.__all__ + } + self.type_dict["SQLDatabase"] = SQLDatabase + # Filter according to settings.utilities + self.type_dict = { + name: utility + for name, utility in self.type_dict.items() + if name in settings.utilities or settings.dev + } + + return self.type_dict def get_signature(self, name: str) -> Optional[Dict]: """Get the signature of a utility.""" try: - if name in get_custom_nodes(self.type_name).keys(): - return get_custom_nodes(self.type_name)[name] - return build_template_from_class(name, utility_type_to_cls_dict) + custom_nodes = get_custom_nodes(self.type_name) + if name in custom_nodes.keys(): + return custom_nodes[name] + return build_template_from_class(name, self.type_to_loader_dict) except ValueError as exc: raise ValueError(f"Utility {name} not found") from exc @@ -29,11 +56,7 @@ class UtilityCreator(LangChainTypeCreator): return None def to_list(self) -> List[str]: - return [ - utility.__name__ - for utility in self.type_to_loader_dict.values() - if utility.__name__ in settings.utilities or settings.dev - ] + return list(self.type_to_loader_dict.keys()) utility_creator = UtilityCreator() diff --git a/src/backend/langflow/template/frontend_node/base.py b/src/backend/langflow/template/frontend_node/base.py index 69fb07752..2714cd4ae 100644 --- a/src/backend/langflow/template/frontend_node/base.py +++ b/src/backend/langflow/template/frontend_node/base.py @@ -143,6 +143,9 @@ class FrontendNode(BaseModel): field.required = False field.advanced = False + field.display_name = key.replace("_", " ").title() + field.display_name = field.display_name.replace("Api", "API") + @staticmethod def should_show_field(key: str, required: bool) -> bool: """Determines whether the field should be shown.""" diff --git a/src/backend/langflow/template/frontend_node/utilities.py b/src/backend/langflow/template/frontend_node/utilities.py new file mode 100644 index 000000000..77d01a23e --- /dev/null +++ b/src/backend/langflow/template/frontend_node/utilities.py @@ -0,0 +1,21 @@ +import json +from typing import Optional + +from langflow.template.field.base import TemplateField +from langflow.template.frontend_node.base import FrontendNode + + +class UtilitiesFrontendNode(FrontendNode): + @staticmethod + def format_field(field: TemplateField, name: Optional[str] = None) -> None: + FrontendNode.format_field(field, name) + # field.field_type could be "Literal['news', 'search', 'places', 'images'] + # we need to convert it to a list + if "Literal" in field.field_type: + field.options = eval(field.field_type.replace("Literal", "")) + field.is_list = True + field.field_type = "str" + + if isinstance(field.value, dict): + field.field_type = "code" + field.value = json.dumps(field.value, indent=4)