From cc785af652dfa070c9da34b3b594c9be870d9e6b Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Sat, 27 May 2023 16:32:56 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(base.py):=20import=20Utiliti?= =?UTF-8?q?esFrontendNode=20from=20the=20correct=20module=20=E2=9C=A8=20fe?= =?UTF-8?q?at(base.py):=20add=20support=20for=20SQLDatabase=20utility=20an?= =?UTF-8?q?d=20filter=20utilities=20according=20to=20settings.utilities=20?= =?UTF-8?q?=F0=9F=8E=A8=20style(frontend=5Fnode/base.py):=20add=20display?= =?UTF-8?q?=5Fname=20to=20fields=20=F0=9F=8E=A8=20style(frontend=5Fnode/ut?= =?UTF-8?q?ilities.py):=20format=20field=20values=20and=20types=20The=20im?= =?UTF-8?q?port=20statement=20for=20UtilitiesFrontendNode=20was=20incorrec?= =?UTF-8?q?t,=20causing=20an=20import=20error.=20The=20import=20statement?= =?UTF-8?q?=20was=20corrected=20to=20import=20from=20the=20correct=20modul?= =?UTF-8?q?e.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for SQLDatabase utility was added to the type_to_loader_dict dictionary. The dictionary is now filtered according to the settings.utilities list. The display_name attribute was added to fields in the FrontendNode class to improve the readability of the frontend. The format_field method in the UtilitiesFrontendNode class was updated to format field values and types. The method now converts field.field_type to a list if it is a Literal type and formats field.value if it is a dictionary. --- .../langflow/interface/utilities/base.py | 43 ++++++++++++++----- .../langflow/template/frontend_node/base.py | 3 ++ .../template/frontend_node/utilities.py | 21 +++++++++ 3 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 src/backend/langflow/template/frontend_node/utilities.py 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)