From 5924aa444249dbd10ec6e2d13a006a9dbfa2cde5 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 29 Jun 2023 08:52:26 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6=20chore(field=5Fformatters.py):=20?= =?UTF-8?q?add=20field=20formatters=20for=20template=20frontend=5Fnode=20?= =?UTF-8?q?=F0=9F=94=A7=20refactor(field=5Fformatters.py):=20refactor=20fi?= =?UTF-8?q?eld=20formatters=20for=20template=20frontend=5Fnode=20The=20com?= =?UTF-8?q?mit=20adds=20a=20new=20file=20`field=5Fformatters.py`=20to=20th?= =?UTF-8?q?e=20`frontend=5Fnode/formatter`=20directory=20in=20the=20`langf?= =?UTF-8?q?low/template`=20backend.=20This=20file=20contains=20multiple=20?= =?UTF-8?q?field=20formatters=20for=20the=20template=20frontend=5Fnode.=20?= =?UTF-8?q?The=20formatters=20handle=20various=20formatting=20tasks=20such?= =?UTF-8?q?=20as=20formatting=20field=20names,=20setting=20field=20options?= =?UTF-8?q?,=20handling=20special=20fields,=20and=20formatting=20field=20t?= =?UTF-8?q?ypes.=20The=20commit=20aims=20to=20improve=20the=20code=20organ?= =?UTF-8?q?ization=20and=20maintainability=20by=20separating=20the=20field?= =?UTF-8?q?=20formatting=20logic=20into=20dedicated=20formatters.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../formatter/field_formatters.py | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/backend/langflow/template/frontend_node/formatter/field_formatters.py diff --git a/src/backend/langflow/template/frontend_node/formatter/field_formatters.py b/src/backend/langflow/template/frontend_node/formatter/field_formatters.py new file mode 100644 index 000000000..7987b134a --- /dev/null +++ b/src/backend/langflow/template/frontend_node/formatter/field_formatters.py @@ -0,0 +1,162 @@ +from typing import Optional +from langflow.template.field.base import TemplateField +from langflow.template.frontend_node.constants import FORCE_SHOW_FIELDS +from langflow.template.frontend_node.formatter.base import FieldFormatter +import re + +from langflow.utils.constants import ( + ANTHROPIC_MODELS, + CHAT_OPENAI_MODELS, + OPENAI_MODELS, +) + + +class OpenAIAPIKeyFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + if "api_key" in field.name and "OpenAI" in str(name): + field.display_name = "OpenAI API Key" + field.required = False + if field.value is None: + field.value = "" + + +class ModelSpecificFieldFormatter(FieldFormatter): + MODEL_DICT = { + "OpenAI": OPENAI_MODELS, + "ChatOpenAI": CHAT_OPENAI_MODELS, + "Anthropic": ANTHROPIC_MODELS, + "ChatAnthropic": ANTHROPIC_MODELS, + } + + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + if name in self.MODEL_DICT and field.name == "model_name": + field.options = self.MODEL_DICT[name] + field.is_list = True + + +class KwargsFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + if "kwargs" in field.name.lower(): + field.advanced = True + field.required = False + field.show = False + + +class APIKeyFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + if "api" in field.name.lower() and "key" in field.name.lower(): + field.required = False + field.advanced = False + + field.display_name = field.name.replace("_", " ").title() + field.display_name = field.display_name.replace("Api", "API") + + +class RemoveOptionalFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + _type = field.field_type + field.field_type = re.sub(r"Optional\[(.*)\]", r"\1", _type) + + +class ListTypeFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + _type = field.field_type + is_list = "List" in _type or "Sequence" in _type + if is_list: + _type = re.sub(r"(List|Sequence)\[(.*)\]", r"\2", _type) + field.is_list = True + field.field_type = _type + + +class DictTypeFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + _type = field.field_type + _type = _type.replace("Mapping", "dict") + field.field_type = _type + + +class UnionTypeFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + _type = field.field_type + if "Union" in _type: + _type = _type.replace("Union[", "")[:-1] + _type = _type.split(",")[0] + _type = _type.replace("]", "").replace("[", "") + field.field_type = _type + + +class SpecialFieldFormatter(FieldFormatter): + SPECIAL_FIELD_HANDLERS = { + "allowed_tools": lambda field: "Tool", + "max_value_length": lambda field: "int", + } + + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + handler = self.SPECIAL_FIELD_HANDLERS.get(field.name) + field.field_type = handler(field) if handler else field.field_type + + +class ShowFieldFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + key = field.name + required = field.required + field.show = ( + (required and key not in ["input_variables"]) + or key in FORCE_SHOW_FIELDS + or "api" in key + or ("key" in key and "input" not in key and "output" not in key) + ) + + +class PasswordFieldFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + key = field.name + show = field.show + if ( + any(text in key.lower() for text in {"password", "token", "api", "key"}) + and show + ): + field.password = True + + +class MultilineFieldFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + key = field.name + if key in { + "suffix", + "prefix", + "template", + "examples", + "code", + "headers", + "description", + }: + field.multiline = True + + +class DefaultValueFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + value = field.to_dict() + if "default" in value: + field.value = value["default"] + + +class HeadersDefaultValueFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + key = field.name + if key == "headers": + field.value = """{'Authorization': 'Bearer '}""" + + +class DictCodeFileFormatter(FieldFormatter): + def format(self, field: TemplateField, name: Optional[str] = None) -> None: + key = field.name + value = field.to_dict() + _type = value["type"] + if "dict" in _type.lower(): + if key == "dict_": + field.field_type = "file" + field.suffixes = [".json", ".yaml", ".yml"] + field.file_types = ["json", "yaml", "yml"] + else: + field.field_type = "code"