Refactor build_template_config to use CustomComponent
This commit is contained in:
parent
1d31ee753b
commit
493a64381c
8 changed files with 65 additions and 86 deletions
|
|
@ -3,12 +3,9 @@ from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, List
|
from typing import TYPE_CHECKING, List
|
||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from langchain_core.documents import Document
|
|
||||||
from langflow.services.store.schema import StoreComponentCreate
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
from langflow.services.store.schema import StoreComponentCreate
|
from langflow.services.store.schema import StoreComponentCreate
|
||||||
from langflow.services.store.utils import get_lf_version_from_pypi
|
from langflow.services.store.utils import get_lf_version_from_pypi
|
||||||
|
from platformdirs import user_cache_dir
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.services.database.models.flow.model import Flow
|
from langflow.services.database.models.flow.model import Flow
|
||||||
|
|
@ -173,37 +170,19 @@ async def check_langflow_version(component: StoreComponentCreate):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def format_elapsed_time(elapsed_time: float) -> str:
|
def format_elapsed_time(elapsed_time) -> str:
|
||||||
"""Format elapsed time to a human-readable format coming from perf_counter().
|
# Format elapsed time to human readable format coming from
|
||||||
|
# perf_counter()
|
||||||
- Less than 1 second: returns milliseconds
|
# If the elapsed time is less than 1 second, return ms
|
||||||
- Less than 1 minute: returns seconds rounded to 2 decimals
|
# If the elapsed time is less than 1 minute, return seconds rounded to 2 decimals
|
||||||
- 1 minute or more: returns minutes and seconds
|
time_str = ""
|
||||||
"""
|
|
||||||
if elapsed_time < 1:
|
if elapsed_time < 1:
|
||||||
milliseconds = int(round(elapsed_time * 1000))
|
elapsed_time = int(round(elapsed_time * 1000))
|
||||||
return f"{milliseconds} ms"
|
time_str = f"{elapsed_time} ms"
|
||||||
elif elapsed_time < 60:
|
elif elapsed_time < 60:
|
||||||
seconds = round(elapsed_time, 2)
|
elapsed_time = round(elapsed_time, 2)
|
||||||
unit = "second" if seconds == 1 else "seconds"
|
time_str = f"{elapsed_time} seconds"
|
||||||
return f"{seconds} {unit}"
|
|
||||||
else:
|
else:
|
||||||
minutes = int(elapsed_time // 60)
|
elapsed_time = round(elapsed_time / 60, 2)
|
||||||
seconds = round(elapsed_time % 60, 2)
|
time_str = f"{elapsed_time} minutes"
|
||||||
minutes_unit = "minute" if minutes == 1 else "minutes"
|
return time_str
|
||||||
seconds_unit = "second" if seconds == 1 else "seconds"
|
|
||||||
return f"{minutes} {minutes_unit}, {seconds} {seconds_unit}"
|
|
||||||
|
|
||||||
|
|
||||||
def serialize_field(value):
|
|
||||||
"""Unified serialization function for handling both BaseModel and Document types,
|
|
||||||
including handling lists of these types."""
|
|
||||||
if isinstance(value, (list, tuple)):
|
|
||||||
return [serialize_field(v) for v in value]
|
|
||||||
elif isinstance(value, Document):
|
|
||||||
return value.to_json()
|
|
||||||
elif isinstance(value, BaseModel):
|
|
||||||
return value.model_dump()
|
|
||||||
elif isinstance(value, str):
|
|
||||||
return {"result": value}
|
|
||||||
return value
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import ast
|
|
||||||
import operator
|
import operator
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Any, ClassVar, Optional
|
from typing import Any, ClassVar, Optional
|
||||||
|
|
@ -7,6 +6,7 @@ from cachetools import TTLCache, cachedmethod
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from langflow.interface.custom.code_parser import CodeParser
|
from langflow.interface.custom.code_parser import CodeParser
|
||||||
|
from langflow.interface.custom.eval import eval_custom_component_code
|
||||||
from langflow.utils import validate
|
from langflow.utils import validate
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -63,26 +63,29 @@ class Component:
|
||||||
|
|
||||||
return validate.create_function(self.code, self._function_entrypoint_name)
|
return validate.create_function(self.code, self._function_entrypoint_name)
|
||||||
|
|
||||||
def build_template_config(self, attributes) -> dict:
|
def getattr_return_str(self, component, attribute):
|
||||||
|
attribute = getattr(component, attribute)
|
||||||
|
return str(attribute) if attribute else ""
|
||||||
|
|
||||||
|
def build_template_config(self) -> dict:
|
||||||
|
if not self.code:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
cc_class = eval_custom_component_code(self.code)
|
||||||
|
component_instance = cc_class()
|
||||||
template_config = {}
|
template_config = {}
|
||||||
|
attributes_func_mapping = {
|
||||||
|
"display_name": self.getattr_return_str,
|
||||||
|
"description": self.getattr_return_str,
|
||||||
|
"beta": self.getattr_return_str,
|
||||||
|
"documentation": self.getattr_return_str,
|
||||||
|
}
|
||||||
|
|
||||||
for item in attributes:
|
for attribute, func in attributes_func_mapping.items():
|
||||||
item_name = item.get("name")
|
if hasattr(component_instance, attribute):
|
||||||
|
template_config[attribute] = func(component_instance, attribute)
|
||||||
|
|
||||||
if item_value := item.get("value"):
|
return template_config
|
||||||
if "display_name" in item_name:
|
|
||||||
template_config["display_name"] = ast.literal_eval(item_value)
|
|
||||||
|
|
||||||
elif "description" in item_name:
|
|
||||||
template_config["description"] = ast.literal_eval(item_value)
|
|
||||||
|
|
||||||
elif "beta" in item_name:
|
|
||||||
template_config["beta"] = ast.literal_eval(item_value)
|
|
||||||
|
|
||||||
elif "documentation" in item_name:
|
|
||||||
template_config["documentation"] = ast.literal_eval(item_value)
|
|
||||||
|
|
||||||
return template_config
|
|
||||||
|
|
||||||
def build(self, *args: Any, **kwargs: Any) -> Any:
|
def build(self, *args: Any, **kwargs: Any) -> Any:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from uuid import UUID
|
||||||
import yaml
|
import yaml
|
||||||
from cachetools import TTLCache, cachedmethod
|
from cachetools import TTLCache, cachedmethod
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
from langflow.interface.custom.code_parser.utils import (
|
from langflow.interface.custom.code_parser.utils import (
|
||||||
extract_inner_type_from_generic_alias,
|
extract_inner_type_from_generic_alias,
|
||||||
extract_union_types_from_generic_alias,
|
extract_union_types_from_generic_alias,
|
||||||
|
|
@ -137,20 +138,6 @@ class CustomComponent(Component):
|
||||||
def template_config(self):
|
def template_config(self):
|
||||||
return self.build_template_config()
|
return self.build_template_config()
|
||||||
|
|
||||||
def build_template_config(self):
|
|
||||||
if not self.code:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
attributes = [
|
|
||||||
main_class["attributes"]
|
|
||||||
for main_class in self.tree.get("classes", [])
|
|
||||||
if main_class["name"] == self.get_main_class_name
|
|
||||||
]
|
|
||||||
# Get just the first item
|
|
||||||
attributes = next(iter(attributes), [])
|
|
||||||
|
|
||||||
return super().build_template_config(attributes)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def keys(self):
|
def keys(self):
|
||||||
def get_credential(name: str):
|
def get_credential(name: str):
|
||||||
|
|
|
||||||
12
src/backend/langflow/interface/custom/eval.py
Normal file
12
src/backend/langflow/interface/custom/eval.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
from typing import TYPE_CHECKING, Type
|
||||||
|
|
||||||
|
from langflow.utils import validate
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from langflow.interface.custom.custom_component import CustomComponent
|
||||||
|
|
||||||
|
|
||||||
|
def eval_custom_component_code(code: str) -> Type["CustomComponent"]:
|
||||||
|
"""Evaluate custom component code"""
|
||||||
|
class_name = validate.extract_class_name(code)
|
||||||
|
return validate.create_class(code, class_name)
|
||||||
|
|
@ -7,6 +7,8 @@ from typing import Any, Dict, List, Optional, Union
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from langflow.field_typing.range_spec import RangeSpec
|
from langflow.field_typing.range_spec import RangeSpec
|
||||||
from langflow.interface.custom.code_parser.utils import extract_inner_type
|
from langflow.interface.custom.code_parser.utils import extract_inner_type
|
||||||
from langflow.interface.custom.custom_component import CustomComponent
|
from langflow.interface.custom.custom_component import CustomComponent
|
||||||
|
|
@ -15,11 +17,11 @@ from langflow.interface.custom.directory_reader.utils import (
|
||||||
determine_component_name,
|
determine_component_name,
|
||||||
merge_nested_dicts_with_renaming,
|
merge_nested_dicts_with_renaming,
|
||||||
)
|
)
|
||||||
from langflow.interface.importing.utils import eval_custom_component_code
|
from langflow.interface.custom.eval import eval_custom_component_code
|
||||||
from langflow.template.field.base import TemplateField
|
from langflow.template.field.base import TemplateField
|
||||||
from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode
|
from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode
|
||||||
|
from langflow.utils import validate
|
||||||
from langflow.utils.util import get_base_classes
|
from langflow.utils.util import get_base_classes
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
|
|
||||||
def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]):
|
def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]):
|
||||||
|
|
@ -370,3 +372,10 @@ def build_component(component):
|
||||||
component_template = create_component_template(component)
|
component_template = create_component_template(component)
|
||||||
logger.debug(f"Building component: {component_name, component.get('output_types')}")
|
logger.debug(f"Building component: {component_name, component.get('output_types')}")
|
||||||
return component_name, component_template
|
return component_name, component_template
|
||||||
|
|
||||||
|
|
||||||
|
def get_function(code):
|
||||||
|
"""Get the function"""
|
||||||
|
function_name = validate.extract_function_name(code)
|
||||||
|
|
||||||
|
return validate.create_function(code, function_name)
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ from langchain.chains.base import Chain
|
||||||
from langchain.prompts import PromptTemplate
|
from langchain.prompts import PromptTemplate
|
||||||
from langchain.tools import BaseTool
|
from langchain.tools import BaseTool
|
||||||
from langchain_core.language_models.chat_models import BaseChatModel
|
from langchain_core.language_models.chat_models import BaseChatModel
|
||||||
|
|
||||||
from langflow.interface.custom.custom_component import CustomComponent
|
from langflow.interface.custom.custom_component import CustomComponent
|
||||||
from langflow.interface.wrappers.base import wrapper_creator
|
from langflow.interface.wrappers.base import wrapper_creator
|
||||||
from langflow.utils import validate
|
|
||||||
|
|
||||||
|
|
||||||
def import_module(module_path: str) -> Any:
|
def import_module(module_path: str) -> Any:
|
||||||
|
|
@ -171,16 +171,3 @@ def import_utility(utility: str) -> Any:
|
||||||
if utility == "SQLDatabase":
|
if utility == "SQLDatabase":
|
||||||
return import_class(f"langchain_community.sql_database.{utility}")
|
return import_class(f"langchain_community.sql_database.{utility}")
|
||||||
return import_class(f"langchain_community.utilities.{utility}")
|
return import_class(f"langchain_community.utilities.{utility}")
|
||||||
|
|
||||||
|
|
||||||
def get_function(code):
|
|
||||||
"""Get the function"""
|
|
||||||
function_name = validate.extract_function_name(code)
|
|
||||||
|
|
||||||
return validate.create_function(code, function_name)
|
|
||||||
|
|
||||||
|
|
||||||
def eval_custom_component_code(code: str) -> Type[CustomComponent]:
|
|
||||||
"""Evaluate custom component code"""
|
|
||||||
class_name = validate.extract_class_name(code)
|
|
||||||
return validate.create_class(code, class_name)
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,10 @@ from langchain_core.documents import Document
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
|
from langflow.interface.custom.eval import eval_custom_component_code
|
||||||
|
from langflow.interface.custom.utils import get_function
|
||||||
from langflow.interface.custom_lists import CUSTOM_NODES
|
from langflow.interface.custom_lists import CUSTOM_NODES
|
||||||
from langflow.interface.importing.utils import eval_custom_component_code, get_function, import_by_type
|
from langflow.interface.importing.utils import import_by_type
|
||||||
from langflow.interface.initialize.llm import initialize_vertexai
|
from langflow.interface.initialize.llm import initialize_vertexai
|
||||||
from langflow.interface.initialize.utils import handle_format_kwargs, handle_node_type, handle_partial_variables
|
from langflow.interface.initialize.utils import handle_format_kwargs, handle_node_type, handle_partial_variables
|
||||||
from langflow.interface.initialize.vector_store import vecstore_initializer
|
from langflow.interface.initialize.vector_store import vecstore_initializer
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
from langflow.interface.importing.utils import get_function
|
|
||||||
|
|
||||||
|
from langchain.agents.tools import Tool
|
||||||
from pydantic.v1 import BaseModel, validator
|
from pydantic.v1 import BaseModel, validator
|
||||||
|
|
||||||
|
from langflow.interface.custom.utils import get_function
|
||||||
from langflow.utils import validate
|
from langflow.utils import validate
|
||||||
from langchain.agents.tools import Tool
|
|
||||||
|
|
||||||
|
|
||||||
class Function(BaseModel):
|
class Function(BaseModel):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue