📝 (text.py): Rename CustomComponent to Component for better clarity and consistency
📝 (ChatInput.py, TextInput.py, ChatOutput.py, RecordsOutput.py, TextOutput.py): Refactor code to use Input and Output classes for defining inputs and outputs 📝 (CustomComponent.py): Update method to get the build method for custom components to consider classes inheriting from Component or CustomComponent 📝 (DirectoryReader.py): Remove check for missing build function as it is no longer necessary 📝 (base.py): Add properties to easily access outgoing edges, incoming edges, and source names of edges in a Vertex object ♻️ (types.py): Refactor code to improve readability and maintainability by adding type hinting and organizing imports 📝 (types.py): Add missing documentation and comments to clarify the purpose of methods and classes ♻️ (loading.py): Refactor code to remove redundant code and improve code structure for better maintainability 📝 (loading.py): Add comments to explain the purpose of functions and the flow of the code ♻️ (base.py): Refactor code to improve consistency and readability by updating class names and method calls to match the intended functionality
This commit is contained in:
parent
7fb5644a87
commit
daedaae820
12 changed files with 192 additions and 82 deletions
|
|
@ -1,12 +1,12 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from langflow.custom import CustomComponent
|
from langflow.custom import Component
|
||||||
from langflow.field_typing import Text
|
from langflow.field_typing import Text
|
||||||
from langflow.helpers.record import records_to_text
|
from langflow.helpers.record import records_to_text
|
||||||
from langflow.schema.schema import Record
|
from langflow.schema.schema import Record
|
||||||
|
|
||||||
|
|
||||||
class TextComponent(CustomComponent):
|
class TextComponent(Component):
|
||||||
display_name = "Text Component"
|
display_name = "Text Component"
|
||||||
description = "Used to pass text to the next component."
|
description = "Used to pass text to the next component."
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class ChatInput(ChatComponent):
|
||||||
]
|
]
|
||||||
|
|
||||||
def text_response(self) -> Text:
|
def text_response(self) -> Text:
|
||||||
result = self.message
|
result = self.input_value
|
||||||
if self.session_id and isinstance(result, (Record, str)):
|
if self.session_id and isinstance(result, (Record, str)):
|
||||||
self.store_message(result, self.session_id, self.sender, self.sender_name)
|
self.store_message(result, self.session_id, self.sender, self.sender_name)
|
||||||
return result
|
return result
|
||||||
|
|
@ -29,11 +29,12 @@ class ChatInput(ChatComponent):
|
||||||
def record_response(self) -> Record:
|
def record_response(self) -> Record:
|
||||||
record = Record(
|
record = Record(
|
||||||
data={
|
data={
|
||||||
"message": self.message,
|
"message": self.input_value,
|
||||||
"sender": self.sender,
|
"sender": self.sender,
|
||||||
"sender_name": self.sender_name,
|
"sender_name": self.sender_name,
|
||||||
"session_id": self.session_id,
|
"session_id": self.session_id,
|
||||||
}
|
},
|
||||||
|
text_key="message",
|
||||||
)
|
)
|
||||||
if self.session_id and isinstance(record, (Record, str)):
|
if self.session_id and isinstance(record, (Record, str)):
|
||||||
self.store_message(record, self.session_id, self.sender, self.sender_name)
|
self.store_message(record, self.session_id, self.sender, self.sender_name)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from langflow.base.io.text import TextComponent
|
from langflow.base.io.text import TextComponent
|
||||||
from langflow.field_typing import Text
|
from langflow.field_typing import Text
|
||||||
|
from langflow.template import Input, Output
|
||||||
|
|
||||||
|
|
||||||
class TextInput(TextComponent):
|
class TextInput(TextComponent):
|
||||||
|
|
@ -9,24 +8,26 @@ class TextInput(TextComponent):
|
||||||
description = "Get text inputs from the Playground."
|
description = "Get text inputs from the Playground."
|
||||||
icon = "type"
|
icon = "type"
|
||||||
|
|
||||||
def build_config(self):
|
inputs = [
|
||||||
return {
|
Input(
|
||||||
"input_value": {
|
name="input_value",
|
||||||
"display_name": "Value",
|
type=str,
|
||||||
"input_types": ["Record", "Text"],
|
display_name="Value",
|
||||||
"info": "Text or Record to be passed as input.",
|
info="Text or Record to be passed as input.",
|
||||||
},
|
input_types=["Record", "Text"],
|
||||||
"record_template": {
|
),
|
||||||
"display_name": "Record Template",
|
Input(
|
||||||
"multiline": True,
|
name="record_template",
|
||||||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
type=str,
|
||||||
"advanced": True,
|
display_name="Record Template",
|
||||||
},
|
multiline=True,
|
||||||
}
|
info="Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||||
|
advanced=True,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
outputs = [
|
||||||
|
Output(name="Text", method="text_response"),
|
||||||
|
]
|
||||||
|
|
||||||
def build(
|
def text_response(self) -> Text:
|
||||||
self,
|
return self.input_value if self.input_value else ""
|
||||||
input_value: Optional[Text] = "",
|
|
||||||
record_template: Optional[str] = "",
|
|
||||||
) -> Text:
|
|
||||||
return super().build(input_value=input_value, record_template=record_template)
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
from typing import Optional, Union
|
|
||||||
|
|
||||||
from langflow.base.io.chat import ChatComponent
|
from langflow.base.io.chat import ChatComponent
|
||||||
from langflow.field_typing import Text
|
from langflow.field_typing import Text
|
||||||
from langflow.schema import Record
|
from langflow.schema import Record
|
||||||
|
from langflow.template import Input, Output
|
||||||
|
|
||||||
|
|
||||||
class ChatOutput(ChatComponent):
|
class ChatOutput(ChatComponent):
|
||||||
|
|
@ -10,20 +9,34 @@ class ChatOutput(ChatComponent):
|
||||||
description = "Display a chat message in the Playground."
|
description = "Display a chat message in the Playground."
|
||||||
icon = "ChatOutput"
|
icon = "ChatOutput"
|
||||||
|
|
||||||
def build(
|
inputs = [
|
||||||
self,
|
Input(name="input_value", type=str, display_name="Message", multiline=True),
|
||||||
sender: Optional[str] = "Machine",
|
Input(name="sender", type=str, display_name="Sender Type", options=["Machine", "AI"]),
|
||||||
sender_name: Optional[str] = "AI",
|
Input(name="sender_name", type=str, display_name="Sender Name"),
|
||||||
input_value: Optional[str] = None,
|
Input(name="session_id", type=str, display_name="Session ID"),
|
||||||
session_id: Optional[str] = None,
|
Input(name="record_template", type=str, display_name="Record Template", default="{text}"),
|
||||||
return_record: Optional[bool] = False,
|
]
|
||||||
record_template: Optional[str] = "{text}",
|
outputs = [
|
||||||
) -> Union[Text, Record]:
|
Output(name="Message", method="text_response"),
|
||||||
return super().build_with_record(
|
Output(name="Record", method="record_response"),
|
||||||
sender=sender,
|
]
|
||||||
sender_name=sender_name,
|
|
||||||
input_value=input_value,
|
def text_response(self) -> Text:
|
||||||
session_id=session_id,
|
result = self.input_value
|
||||||
return_record=return_record,
|
if self.session_id and isinstance(result, (Record, str)):
|
||||||
record_template=record_template or "",
|
self.store_message(result, self.session_id, self.sender, self.sender_name)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def record_response(self) -> Record:
|
||||||
|
record = Record(
|
||||||
|
data={
|
||||||
|
"message": self.input_value,
|
||||||
|
"sender": self.sender,
|
||||||
|
"sender_name": self.sender_name,
|
||||||
|
"session_id": self.session_id,
|
||||||
|
"template": self.record_template or "",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
if self.session_id and isinstance(record, (Record, str)):
|
||||||
|
self.store_message(record, self.session_id, self.sender, self.sender_name)
|
||||||
|
return record
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,18 @@
|
||||||
from langflow.custom import CustomComponent
|
from langflow.custom import Component
|
||||||
from langflow.schema import Record
|
from langflow.schema import Record
|
||||||
|
from langflow.template import Input, Output
|
||||||
|
|
||||||
|
|
||||||
class RecordsOutput(CustomComponent):
|
class RecordsOutput(Component):
|
||||||
display_name = "Records Output"
|
display_name = "Records Output"
|
||||||
description = "Display Records as a Table"
|
description = "Display Records as a Table"
|
||||||
|
|
||||||
def build(self, input_value: Record) -> Record:
|
inputs = [
|
||||||
return input_value
|
Input(name="input_value", type=Record, display_name="Record Input"),
|
||||||
|
]
|
||||||
|
outputs = [
|
||||||
|
Output(name="Record", method="record_response"),
|
||||||
|
]
|
||||||
|
|
||||||
|
def record_response(self) -> Record:
|
||||||
|
return self.input_value
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from langflow.base.io.text import TextComponent
|
from langflow.base.io.text import TextComponent
|
||||||
from langflow.field_typing import Text
|
from langflow.field_typing import Text
|
||||||
|
from langflow.template import Input, Output
|
||||||
|
|
||||||
|
|
||||||
class TextOutput(TextComponent):
|
class TextOutput(TextComponent):
|
||||||
|
|
@ -9,20 +8,26 @@ class TextOutput(TextComponent):
|
||||||
description = "Display a text output in the Playground."
|
description = "Display a text output in the Playground."
|
||||||
icon = "type"
|
icon = "type"
|
||||||
|
|
||||||
def build_config(self):
|
inputs = [
|
||||||
return {
|
Input(
|
||||||
"input_value": {
|
name="input_value",
|
||||||
"display_name": "Value",
|
type=str,
|
||||||
"input_types": ["Record", "Text"],
|
display_name="Value",
|
||||||
"info": "Text or Record to be passed as output.",
|
info="Text or Record to be passed as output.",
|
||||||
},
|
input_types=["Record", "Text"],
|
||||||
"record_template": {
|
),
|
||||||
"display_name": "Record Template",
|
Input(
|
||||||
"multiline": True,
|
name="record_template",
|
||||||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
type=str,
|
||||||
"advanced": True,
|
display_name="Record Template",
|
||||||
},
|
multiline=True,
|
||||||
}
|
info="Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||||
|
advanced=True,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
outputs = [
|
||||||
|
Output(name="Text", method="text_response"),
|
||||||
|
]
|
||||||
|
|
||||||
def build(self, input_value: Optional[Text] = "", record_template: Optional[str] = "") -> Text:
|
def text_response(self) -> Text:
|
||||||
return super().build(input_value=input_value, record_template=record_template)
|
return self.input_value if self.input_value else ""
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import operator
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Any, Callable, ClassVar, List, Optional, Sequence, Union
|
from typing import TYPE_CHECKING, Any, Callable, ClassVar, List, Optional, Sequence, Union
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from cachetools import TTLCache, cachedmethod
|
from cachetools import TTLCache
|
||||||
from langchain_core.documents import Document
|
from langchain_core.documents import Document
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
@ -299,7 +298,6 @@ class CustomComponent(BaseComponent):
|
||||||
arg["type"] = "Data"
|
arg["type"] = "Data"
|
||||||
return args
|
return args
|
||||||
|
|
||||||
@cachedmethod(operator.attrgetter("cache"))
|
|
||||||
def get_method(self, method_name: str):
|
def get_method(self, method_name: str):
|
||||||
"""
|
"""
|
||||||
Gets the build method for the custom component.
|
Gets the build method for the custom component.
|
||||||
|
|
@ -310,7 +308,9 @@ class CustomComponent(BaseComponent):
|
||||||
if not self.code:
|
if not self.code:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
component_classes = [cls for cls in self.tree["classes"] if self.code_class_base_inheritance in cls["bases"]]
|
component_classes = [
|
||||||
|
cls for cls in self.tree["classes"] if "Component" in cls["bases"] or "CustomComponent" in cls["bases"]
|
||||||
|
]
|
||||||
if not component_classes:
|
if not component_classes:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -301,8 +301,6 @@ class DirectoryReader:
|
||||||
return False, "Empty file"
|
return False, "Empty file"
|
||||||
elif not self.validate_code(file_content):
|
elif not self.validate_code(file_content):
|
||||||
return False, "Syntax error"
|
return False, "Syntax error"
|
||||||
elif not self.validate_build(file_content):
|
|
||||||
return False, "Missing build function"
|
|
||||||
elif self._is_type_hint_used_in_args("Optional", file_content) and not self._is_type_hint_imported(
|
elif self._is_type_hint_used_in_args("Optional", file_content) and not self._is_type_hint_imported(
|
||||||
"Optional", file_content
|
"Optional", file_content
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,18 @@ class Vertex:
|
||||||
def edges(self) -> List["ContractEdge"]:
|
def edges(self) -> List["ContractEdge"]:
|
||||||
return self.graph.get_vertex_edges(self.id)
|
return self.graph.get_vertex_edges(self.id)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def outgoing_edges(self) -> List["ContractEdge"]:
|
||||||
|
return [edge for edge in self.edges if edge.source_id == self.id]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def incoming_edges(self) -> List["ContractEdge"]:
|
||||||
|
return [edge for edge in self.edges if edge.target_id == self.id]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def edges_source_names(self) -> List[str]:
|
||||||
|
return {edge.source_handle.name for edge in self.edges}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def predecessors(self) -> List["Vertex"]:
|
def predecessors(self) -> List["Vertex"]:
|
||||||
return self.graph.get_predecessors(self)
|
return self.graph.get_predecessors(self)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,24 @@
|
||||||
import json
|
import json
|
||||||
from typing import AsyncIterator, Dict, Iterator, List
|
from typing import Any, AsyncIterator, Dict, Iterator, List
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
from git import TYPE_CHECKING
|
||||||
from langchain_core.messages import AIMessage
|
from langchain_core.messages import AIMessage
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from langflow.graph.schema import CHAT_COMPONENTS, RECORDS_COMPONENTS, InterfaceComponentTypes
|
from langflow.graph.schema import CHAT_COMPONENTS, RECORDS_COMPONENTS, InterfaceComponentTypes
|
||||||
from langflow.graph.utils import UnbuiltObject, serialize_field
|
from langflow.graph.utils import UnbuiltObject, serialize_field
|
||||||
from langflow.graph.vertex.base import Vertex
|
from langflow.graph.vertex.base import Vertex
|
||||||
|
from langflow.graph.vertex.utils import log_transaction
|
||||||
from langflow.schema import Record
|
from langflow.schema import Record
|
||||||
from langflow.schema.schema import INPUT_FIELD_NAME
|
from langflow.schema.schema import INPUT_FIELD_NAME
|
||||||
from langflow.services.monitor.utils import log_vertex_build
|
from langflow.services.monitor.utils import log_vertex_build
|
||||||
from langflow.utils.schemas import ChatOutputResponse, RecordOutputResponse
|
from langflow.utils.schemas import ChatOutputResponse, RecordOutputResponse
|
||||||
from langflow.utils.util import unescape_string
|
from langflow.utils.util import unescape_string
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from langflow.graph.edge.base import ContractEdge
|
||||||
|
|
||||||
|
|
||||||
class CustomComponentVertex(Vertex):
|
class CustomComponentVertex(Vertex):
|
||||||
def __init__(self, data: Dict, graph):
|
def __init__(self, data: Dict, graph):
|
||||||
|
|
@ -32,10 +37,65 @@ class ComponentVertex(Vertex):
|
||||||
if self.artifacts and "repr" in self.artifacts:
|
if self.artifacts and "repr" in self.artifacts:
|
||||||
return self.artifacts["repr"] or super()._built_object_repr()
|
return self.artifacts["repr"] or super()._built_object_repr()
|
||||||
|
|
||||||
|
def _update_built_object_and_artifacts(self, result):
|
||||||
|
"""
|
||||||
|
Updates the built object and its artifacts.
|
||||||
|
"""
|
||||||
|
if isinstance(result, tuple):
|
||||||
|
if len(result) == 2:
|
||||||
|
self._built_object, self.artifacts = result
|
||||||
|
elif len(result) == 3:
|
||||||
|
self._custom_component, self._built_object, self.artifacts = result
|
||||||
|
else:
|
||||||
|
self._built_object = result
|
||||||
|
|
||||||
class InterfaceVertex(Vertex):
|
for key, value in self._built_object.items():
|
||||||
|
self.add_result(key, value)
|
||||||
|
|
||||||
|
def get_edge_with_target(self, target_id: str) -> "ContractEdge":
|
||||||
|
"""
|
||||||
|
Get the edge with the target id.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
target_id: The target id of the edge.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The edge with the target id.
|
||||||
|
"""
|
||||||
|
for edge in self.edges:
|
||||||
|
if edge.target_id == target_id:
|
||||||
|
return edge
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def _get_result(self, requester: "Vertex") -> Any:
|
||||||
|
"""
|
||||||
|
Retrieves the result of the built component.
|
||||||
|
|
||||||
|
If the component has not been built yet, a ValueError is raised.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The built result if use_result is True, else the built object.
|
||||||
|
"""
|
||||||
|
if not self._built:
|
||||||
|
log_transaction(source=self, target=requester, flow_id=self.graph.flow_id, status="error")
|
||||||
|
raise ValueError(f"Component {self.display_name} has not been built yet")
|
||||||
|
|
||||||
|
if requester is None:
|
||||||
|
raise ValueError("Requester Vertex is None")
|
||||||
|
|
||||||
|
edge = self.get_edge_with_target(requester.id)
|
||||||
|
if edge is None:
|
||||||
|
raise ValueError(f"Edge not found between {self.display_name} and {requester.display_name}")
|
||||||
|
|
||||||
|
result = self.results[edge.source_handle.name]
|
||||||
|
|
||||||
|
log_transaction(source=self, target=requester, flow_id=self.graph.flow_id, status="success")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class InterfaceVertex(ComponentVertex):
|
||||||
def __init__(self, data: Dict, graph):
|
def __init__(self, data: Dict, graph):
|
||||||
super().__init__(data, graph=graph, base_type="custom_components", is_task=True)
|
super().__init__(data, graph=graph)
|
||||||
self.steps = [self._build, self._run]
|
self.steps = [self._build, self._run]
|
||||||
|
|
||||||
def build_stream_url(self):
|
def build_stream_url(self):
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,15 @@ import os
|
||||||
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Type
|
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Type
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
|
import yaml
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from langflow.custom.eval import eval_custom_component_code
|
from langflow.custom.eval import eval_custom_component_code
|
||||||
from langflow.schema.schema import Record
|
from langflow.schema.schema import Record
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.custom import CustomComponent
|
from langflow.custom import Component, CustomComponent
|
||||||
from langflow.graph.vertex.base import Vertex
|
from langflow.graph.vertex.base import Vertex
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -32,6 +34,7 @@ async def instantiate_class(
|
||||||
raise ValueError("No base type provided for vertex")
|
raise ValueError("No base type provided for vertex")
|
||||||
|
|
||||||
params_copy = params.copy()
|
params_copy = params.copy()
|
||||||
|
# Remove code from params
|
||||||
class_object: Type["CustomComponent"] = eval_custom_component_code(params_copy.pop("code"))
|
class_object: Type["CustomComponent"] = eval_custom_component_code(params_copy.pop("code"))
|
||||||
custom_component: "CustomComponent" = class_object(
|
custom_component: "CustomComponent" = class_object(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
|
|
@ -43,9 +46,9 @@ async def instantiate_class(
|
||||||
custom_component, params_copy, vertex.load_from_db_fields, fallback_to_env_vars
|
custom_component, params_copy, vertex.load_from_db_fields, fallback_to_env_vars
|
||||||
)
|
)
|
||||||
if base_type == "custom_components":
|
if base_type == "custom_components":
|
||||||
return await build_custom_component(params=params, custom_component=custom_component)
|
return await build_custom_component(params=params_copy, custom_component=custom_component)
|
||||||
elif base_type == "component":
|
elif base_type == "component":
|
||||||
return await build_component(params=params, custom_component=custom_component)
|
return await build_component(params=params_copy, custom_component=custom_component, vertex=vertex)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Base type {base_type} not found.")
|
raise ValueError(f"Base type {base_type} not found.")
|
||||||
|
|
||||||
|
|
@ -111,7 +114,7 @@ def update_params_with_load_from_db_fields(
|
||||||
|
|
||||||
async def build_component(
|
async def build_component(
|
||||||
params: dict,
|
params: dict,
|
||||||
custom_component: "CustomComponent",
|
custom_component: "Component",
|
||||||
vertex: "Vertex",
|
vertex: "Vertex",
|
||||||
):
|
):
|
||||||
# Now set the params as attributes of the custom_component
|
# Now set the params as attributes of the custom_component
|
||||||
|
|
@ -122,7 +125,7 @@ async def build_component(
|
||||||
for output in custom_component.outputs:
|
for output in custom_component.outputs:
|
||||||
# Build the output if it's connected to some other vertex
|
# Build the output if it's connected to some other vertex
|
||||||
# or if it's not connected to any vertex
|
# or if it's not connected to any vertex
|
||||||
if not vertex.edges or output.name in vertex.edges:
|
if not vertex.outgoing_edges or output.name in vertex.edges_source_names:
|
||||||
method: Callable | Awaitable = getattr(custom_component, output.method)
|
method: Callable | Awaitable = getattr(custom_component, output.method)
|
||||||
result = method()
|
result = method()
|
||||||
# If the method is asynchronous, we need to await it
|
# If the method is asynchronous, we need to await it
|
||||||
|
|
@ -130,6 +133,15 @@ async def build_component(
|
||||||
result = await result
|
result = await result
|
||||||
build_result[output.name] = result
|
build_result[output.name] = result
|
||||||
custom_repr = custom_component.custom_repr()
|
custom_repr = custom_component.custom_repr()
|
||||||
|
|
||||||
|
# ! Temporary REPR
|
||||||
|
# Since all are dict, yaml.dump them
|
||||||
|
if isinstance(build_result, dict):
|
||||||
|
_build_result = {
|
||||||
|
key: value.model_dump() if isinstance(value, BaseModel) else value for key, value in build_result.items()
|
||||||
|
}
|
||||||
|
custom_repr = yaml.dump(_build_result)
|
||||||
|
|
||||||
if custom_repr is None and isinstance(build_result, (dict, Record, str)):
|
if custom_repr is None and isinstance(build_result, (dict, Record, str)):
|
||||||
custom_repr = build_result
|
custom_repr = build_result
|
||||||
if not isinstance(custom_repr, str):
|
if not isinstance(custom_repr, str):
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,6 @@ class FrontendNode(BaseModel):
|
||||||
if "inputs" not in kwargs:
|
if "inputs" not in kwargs:
|
||||||
raise ValueError("Missing 'inputs' argument.")
|
raise ValueError("Missing 'inputs' argument.")
|
||||||
inputs = kwargs.pop("inputs")
|
inputs = kwargs.pop("inputs")
|
||||||
template = Template(type_name="CustomComponent", fields=inputs)
|
template = Template(type_name="Component", fields=inputs)
|
||||||
kwargs["template"] = template
|
kwargs["template"] = template
|
||||||
return cls(**kwargs)
|
return cls(**kwargs)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue