Refactor code and update dependencies
This commit is contained in:
parent
553624c1be
commit
103dda198a
9 changed files with 135 additions and 82 deletions
|
|
@ -54,10 +54,10 @@ class APIRequest(CustomComponent):
|
||||||
raise ValueError(f"Unsupported method: {method}")
|
raise ValueError(f"Unsupported method: {method}")
|
||||||
|
|
||||||
data = body if body else None
|
data = body if body else None
|
||||||
data = json.dumps(data)
|
payload = json.dumps(data)
|
||||||
try:
|
try:
|
||||||
response = await client.request(
|
response = await client.request(
|
||||||
method, url, headers=headers, content=data, timeout=timeout
|
method, url, headers=headers, content=payload, timeout=timeout
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
result = response.json()
|
result = response.json()
|
||||||
|
|
@ -93,14 +93,13 @@ class APIRequest(CustomComponent):
|
||||||
async def build(
|
async def build(
|
||||||
self,
|
self,
|
||||||
method: str,
|
method: str,
|
||||||
url: List[str],
|
urls: List[str],
|
||||||
headers: Optional[dict] = None,
|
headers: Optional[dict] = None,
|
||||||
body: Optional[List[Record]] = None,
|
body: Optional[List[Record]] = None,
|
||||||
timeout: int = 5,
|
timeout: int = 5,
|
||||||
) -> List[Record]:
|
) -> List[Record]:
|
||||||
if headers is None:
|
if headers is None:
|
||||||
headers = {}
|
headers = {}
|
||||||
urls = url if isinstance(url, list) else [url]
|
|
||||||
bodies = []
|
bodies = []
|
||||||
if body:
|
if body:
|
||||||
if isinstance(body, list):
|
if isinstance(body, list):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Any
|
from typing import Any, Optional
|
||||||
|
|
||||||
from langflow import CustomComponent
|
from langflow import CustomComponent
|
||||||
from langflow.schema import Record
|
from langflow.schema import Record
|
||||||
|
|
@ -62,7 +62,10 @@ class TextToRecordComponent(CustomComponent):
|
||||||
build_config[field.name] = field.to_dict()
|
build_config[field.name] = field.to_dict()
|
||||||
|
|
||||||
def update_build_config(
|
def update_build_config(
|
||||||
self, build_config: dict, field_name: str, field_value: Any
|
self,
|
||||||
|
build_config: dict,
|
||||||
|
field_value: Any,
|
||||||
|
field_name: Optional[str] = None,
|
||||||
):
|
):
|
||||||
if field_name == "mode":
|
if field_name == "mode":
|
||||||
build_config["mode"]["value"] = field_value
|
build_config["mode"]["value"] = field_value
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Any, Text
|
from typing import Any, Optional
|
||||||
|
|
||||||
from langflow import CustomComponent
|
from langflow import CustomComponent
|
||||||
|
|
||||||
|
|
@ -10,7 +10,10 @@ class UUIDGeneratorComponent(CustomComponent):
|
||||||
description = "Generates a unique ID."
|
description = "Generates a unique ID."
|
||||||
|
|
||||||
def update_build_config(
|
def update_build_config(
|
||||||
self, build_config: dict, field_name: Text, field_value: Any
|
self,
|
||||||
|
build_config: dict,
|
||||||
|
field_value: Any,
|
||||||
|
field_name: Optional[str] = None,
|
||||||
):
|
):
|
||||||
if field_name == "unique_id":
|
if field_name == "unique_id":
|
||||||
build_config[field_name]["value"] = str(uuid.uuid4())
|
build_config[field_name]["value"] = str(uuid.uuid4())
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ from collections import defaultdict, deque
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from typing import TYPE_CHECKING, Dict, Generator, List, Optional, Type, Union
|
from typing import TYPE_CHECKING, Dict, Generator, List, Optional, Type, Union
|
||||||
|
|
||||||
from langchain.chains.base import Chain
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from langflow.graph.edge.base import ContractEdge
|
from langflow.graph.edge.base import ContractEdge
|
||||||
|
|
@ -22,7 +21,6 @@ from langflow.graph.vertex.types import (
|
||||||
)
|
)
|
||||||
from langflow.interface.tools.constants import FILE_TOOLS
|
from langflow.interface.tools.constants import FILE_TOOLS
|
||||||
from langflow.schema import Record
|
from langflow.schema import Record
|
||||||
from langflow.utils import payload
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langflow.graph.schema import ResultData
|
from langflow.graph.schema import ResultData
|
||||||
|
|
@ -62,7 +60,7 @@ class Graph:
|
||||||
self.activated_vertices: List[str] = []
|
self.activated_vertices: List[str] = []
|
||||||
self.vertices_layers: List[List[str]] = []
|
self.vertices_layers: List[List[str]] = []
|
||||||
self.vertices_to_run: set[str] = set()
|
self.vertices_to_run: set[str] = set()
|
||||||
self.stop_vertex = None
|
self.stop_vertex: Optional[str] = None
|
||||||
|
|
||||||
self.inactive_vertices: set = set()
|
self.inactive_vertices: set = set()
|
||||||
self.edges: List[ContractEdge] = []
|
self.edges: List[ContractEdge] = []
|
||||||
|
|
@ -196,7 +194,7 @@ class Graph:
|
||||||
async def run(
|
async def run(
|
||||||
self,
|
self,
|
||||||
inputs: list[Dict[str, Union[str, list[str]]]],
|
inputs: list[Dict[str, Union[str, list[str]]]],
|
||||||
outputs: list[str],
|
outputs: Optional[list[str]] = None,
|
||||||
session_id: Optional[str] = None,
|
session_id: Optional[str] = None,
|
||||||
stream: bool = False,
|
stream: bool = False,
|
||||||
) -> List[List[Optional["ResultData"]]]:
|
) -> List[List[Optional["ResultData"]]]:
|
||||||
|
|
@ -210,11 +208,26 @@ class Graph:
|
||||||
if not isinstance(inputs, list):
|
if not isinstance(inputs, list):
|
||||||
inputs = [inputs]
|
inputs = [inputs]
|
||||||
for input_dict in inputs:
|
for input_dict in inputs:
|
||||||
components: list[str] = input_dict.get("components", [])
|
components: Union[str, list[str]] = input_dict.get("components", [])
|
||||||
|
|
||||||
|
if not isinstance(components, list):
|
||||||
|
components = [components]
|
||||||
|
|
||||||
|
if INPUT_FIELD_NAME not in input_dict:
|
||||||
|
input_value = ""
|
||||||
|
else:
|
||||||
|
_input_value = input_dict[INPUT_FIELD_NAME]
|
||||||
|
if isinstance(_input_value, str):
|
||||||
|
input_value = _input_value
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid input value: {input_value}. Expected string"
|
||||||
|
)
|
||||||
|
|
||||||
run_outputs = await self._run(
|
run_outputs = await self._run(
|
||||||
inputs={INPUT_FIELD_NAME: input_dict.get(INPUT_FIELD_NAME, "")},
|
inputs={INPUT_FIELD_NAME: input_value},
|
||||||
input_components=components,
|
input_components=components,
|
||||||
outputs=outputs,
|
outputs=outputs or [],
|
||||||
stream=stream,
|
stream=stream,
|
||||||
session_id=session_id or "",
|
session_id=session_id or "",
|
||||||
)
|
)
|
||||||
|
|
@ -265,7 +278,9 @@ class Graph:
|
||||||
def build_parent_child_map(self):
|
def build_parent_child_map(self):
|
||||||
parent_child_map = defaultdict(list)
|
parent_child_map = defaultdict(list)
|
||||||
for vertex in self.vertices:
|
for vertex in self.vertices:
|
||||||
parent_child_map[vertex.id] = [child.id for child in self.get_successors(vertex)]
|
parent_child_map[vertex.id] = [
|
||||||
|
child.id for child in self.get_successors(vertex)
|
||||||
|
]
|
||||||
return parent_child_map
|
return parent_child_map
|
||||||
|
|
||||||
def increment_run_count(self):
|
def increment_run_count(self):
|
||||||
|
|
@ -296,7 +311,7 @@ class Graph:
|
||||||
return predecessor_map, successor_map
|
return predecessor_map, successor_map
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_payload(cls, payload: Dict, flow_id: str) -> "Graph":
|
def from_payload(cls, payload: Dict, flow_id: Optional[str] = None) -> "Graph":
|
||||||
"""
|
"""
|
||||||
Creates a graph from a payload.
|
Creates a graph from a payload.
|
||||||
|
|
||||||
|
|
@ -479,7 +494,11 @@ class Graph:
|
||||||
return
|
return
|
||||||
self.vertices.remove(vertex)
|
self.vertices.remove(vertex)
|
||||||
self.vertex_map.pop(vertex_id)
|
self.vertex_map.pop(vertex_id)
|
||||||
self.edges = [edge for edge in self.edges if edge.source_id != vertex_id and edge.target_id != vertex_id]
|
self.edges = [
|
||||||
|
edge
|
||||||
|
for edge in self.edges
|
||||||
|
if edge.source_id != vertex_id and edge.target_id != vertex_id
|
||||||
|
]
|
||||||
|
|
||||||
def _build_vertex_params(self) -> None:
|
def _build_vertex_params(self) -> None:
|
||||||
"""Identifies and handles the LLM vertex within the graph."""
|
"""Identifies and handles the LLM vertex within the graph."""
|
||||||
|
|
@ -500,7 +519,9 @@ class Graph:
|
||||||
return
|
return
|
||||||
for vertex in self.vertices:
|
for vertex in self.vertices:
|
||||||
if not self._validate_vertex(vertex):
|
if not self._validate_vertex(vertex):
|
||||||
raise ValueError(f"{vertex.display_name} is not connected to any other components")
|
raise ValueError(
|
||||||
|
f"{vertex.display_name} is not connected to any other components"
|
||||||
|
)
|
||||||
|
|
||||||
def _validate_vertex(self, vertex: Vertex) -> bool:
|
def _validate_vertex(self, vertex: Vertex) -> bool:
|
||||||
"""Validates a vertex."""
|
"""Validates a vertex."""
|
||||||
|
|
@ -541,18 +562,10 @@ class Graph:
|
||||||
vertices.append(vertex)
|
vertices.append(vertex)
|
||||||
return vertices
|
return vertices
|
||||||
|
|
||||||
async def build(self) -> Chain:
|
|
||||||
"""Builds the graph."""
|
|
||||||
# Get root vertex
|
|
||||||
root_vertex = payload.get_root_vertex(self)
|
|
||||||
if root_vertex is None:
|
|
||||||
raise ValueError("No root vertex found")
|
|
||||||
return await root_vertex.build()
|
|
||||||
|
|
||||||
async def process(self) -> "Graph":
|
async def process(self) -> "Graph":
|
||||||
"""Processes the graph with vertices in each layer run in parallel."""
|
"""Processes the graph with vertices in each layer run in parallel."""
|
||||||
vertices_layers = self.sorted_vertices_layers
|
vertices_layers = self.sorted_vertices_layers
|
||||||
vertex_task_run_count = {}
|
vertex_task_run_count: Dict[str, int] = {}
|
||||||
for layer_index, layer in enumerate(vertices_layers):
|
for layer_index, layer in enumerate(vertices_layers):
|
||||||
tasks = []
|
tasks = []
|
||||||
for vertex_id in layer:
|
for vertex_id in layer:
|
||||||
|
|
@ -606,7 +619,9 @@ class Graph:
|
||||||
def dfs(vertex):
|
def dfs(vertex):
|
||||||
if state[vertex] == 1:
|
if state[vertex] == 1:
|
||||||
# We have a cycle
|
# We have a cycle
|
||||||
raise ValueError("Graph contains a cycle, cannot perform topological sort")
|
raise ValueError(
|
||||||
|
"Graph contains a cycle, cannot perform topological sort"
|
||||||
|
)
|
||||||
if state[vertex] == 0:
|
if state[vertex] == 0:
|
||||||
state[vertex] = 1
|
state[vertex] = 1
|
||||||
for edge in vertex.edges:
|
for edge in vertex.edges:
|
||||||
|
|
@ -630,7 +645,10 @@ class Graph:
|
||||||
|
|
||||||
def get_predecessors(self, vertex):
|
def get_predecessors(self, vertex):
|
||||||
"""Returns the predecessors of a vertex."""
|
"""Returns the predecessors of a vertex."""
|
||||||
return [self.get_vertex(source_id) for source_id in self.predecessor_map.get(vertex.id, [])]
|
return [
|
||||||
|
self.get_vertex(source_id)
|
||||||
|
for source_id in self.predecessor_map.get(vertex.id, [])
|
||||||
|
]
|
||||||
|
|
||||||
def get_all_successors(self, vertex, recursive=True, flat=True):
|
def get_all_successors(self, vertex, recursive=True, flat=True):
|
||||||
# Recursively get the successors of the current vertex
|
# Recursively get the successors of the current vertex
|
||||||
|
|
@ -671,7 +689,10 @@ class Graph:
|
||||||
|
|
||||||
def get_successors(self, vertex):
|
def get_successors(self, vertex):
|
||||||
"""Returns the successors of a vertex."""
|
"""Returns the successors of a vertex."""
|
||||||
return [self.get_vertex(target_id) for target_id in self.successor_map.get(vertex.id, [])]
|
return [
|
||||||
|
self.get_vertex(target_id)
|
||||||
|
for target_id in self.successor_map.get(vertex.id, [])
|
||||||
|
]
|
||||||
|
|
||||||
def get_vertex_neighbors(self, vertex: Vertex) -> Dict[Vertex, int]:
|
def get_vertex_neighbors(self, vertex: Vertex) -> Dict[Vertex, int]:
|
||||||
"""Returns the neighbors of a vertex."""
|
"""Returns the neighbors of a vertex."""
|
||||||
|
|
@ -717,7 +738,9 @@ class Graph:
|
||||||
edges_added.add((source.id, target.id))
|
edges_added.add((source.id, target.id))
|
||||||
return edges
|
return edges
|
||||||
|
|
||||||
def _get_vertex_class(self, node_type: str, node_base_type: str, node_id: str) -> Type[Vertex]:
|
def _get_vertex_class(
|
||||||
|
self, node_type: str, node_base_type: str, node_id: str
|
||||||
|
) -> Type[Vertex]:
|
||||||
"""Returns the node class based on the node type."""
|
"""Returns the node class based on the node type."""
|
||||||
# First we check for the node_base_type
|
# First we check for the node_base_type
|
||||||
node_name = node_id.split("-")[0]
|
node_name = node_id.split("-")[0]
|
||||||
|
|
@ -750,14 +773,18 @@ class Graph:
|
||||||
vertex_type: str = vertex_data["type"] # type: ignore
|
vertex_type: str = vertex_data["type"] # type: ignore
|
||||||
vertex_base_type: str = vertex_data["node"]["template"]["_type"] # type: ignore
|
vertex_base_type: str = vertex_data["node"]["template"]["_type"] # type: ignore
|
||||||
|
|
||||||
VertexClass = self._get_vertex_class(vertex_type, vertex_base_type, vertex_data["id"])
|
VertexClass = self._get_vertex_class(
|
||||||
|
vertex_type, vertex_base_type, vertex_data["id"]
|
||||||
|
)
|
||||||
vertex_instance = VertexClass(vertex, graph=self)
|
vertex_instance = VertexClass(vertex, graph=self)
|
||||||
vertex_instance.set_top_level(self.top_level_vertices)
|
vertex_instance.set_top_level(self.top_level_vertices)
|
||||||
vertices.append(vertex_instance)
|
vertices.append(vertex_instance)
|
||||||
|
|
||||||
return vertices
|
return vertices
|
||||||
|
|
||||||
def get_children_by_vertex_type(self, vertex: Vertex, vertex_type: str) -> List[Vertex]:
|
def get_children_by_vertex_type(
|
||||||
|
self, vertex: Vertex, vertex_type: str
|
||||||
|
) -> List[Vertex]:
|
||||||
"""Returns the children of a vertex based on the vertex type."""
|
"""Returns the children of a vertex based on the vertex type."""
|
||||||
children = []
|
children = []
|
||||||
vertex_types = [vertex.data["type"]]
|
vertex_types = [vertex.data["type"]]
|
||||||
|
|
@ -769,7 +796,9 @@ class Graph:
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
vertex_ids = [vertex.id for vertex in self.vertices]
|
vertex_ids = [vertex.id for vertex in self.vertices]
|
||||||
edges_repr = "\n".join([f"{edge.source_id} --> {edge.target_id}" for edge in self.edges])
|
edges_repr = "\n".join(
|
||||||
|
[f"{edge.source_id} --> {edge.target_id}" for edge in self.edges]
|
||||||
|
)
|
||||||
return f"Graph:\nNodes: {vertex_ids}\nConnections:\n{edges_repr}"
|
return f"Graph:\nNodes: {vertex_ids}\nConnections:\n{edges_repr}"
|
||||||
|
|
||||||
def sort_up_to_vertex(self, vertex_id: str, is_start: bool = False) -> List[Vertex]:
|
def sort_up_to_vertex(self, vertex_id: str, is_start: bool = False) -> List[Vertex]:
|
||||||
|
|
@ -912,7 +941,9 @@ class Graph:
|
||||||
|
|
||||||
return refined_layers
|
return refined_layers
|
||||||
|
|
||||||
def sort_chat_inputs_first(self, vertices_layers: List[List[str]]) -> List[List[str]]:
|
def sort_chat_inputs_first(
|
||||||
|
self, vertices_layers: List[List[str]]
|
||||||
|
) -> List[List[str]]:
|
||||||
chat_inputs_first = []
|
chat_inputs_first = []
|
||||||
for layer in vertices_layers:
|
for layer in vertices_layers:
|
||||||
for vertex_id in layer:
|
for vertex_id in layer:
|
||||||
|
|
@ -934,7 +965,7 @@ class Graph:
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
"""Sorts the vertices in the graph."""
|
"""Sorts the vertices in the graph."""
|
||||||
self.mark_all_vertices("ACTIVE")
|
self.mark_all_vertices("ACTIVE")
|
||||||
if stop_component_id:
|
if stop_component_id is not None:
|
||||||
self.stop_vertex = stop_component_id
|
self.stop_vertex = stop_component_id
|
||||||
vertices = self.sort_up_to_vertex(stop_component_id)
|
vertices = self.sort_up_to_vertex(stop_component_id)
|
||||||
elif start_component_id:
|
elif start_component_id:
|
||||||
|
|
@ -966,11 +997,15 @@ class Graph:
|
||||||
self.vertices_to_run.remove(vertex_id)
|
self.vertices_to_run.remove(vertex_id)
|
||||||
return should_run
|
return should_run
|
||||||
|
|
||||||
def sort_interface_components_first(self, vertices_layers: List[List[str]]) -> List[List[str]]:
|
def sort_interface_components_first(
|
||||||
|
self, vertices_layers: List[List[str]]
|
||||||
|
) -> List[List[str]]:
|
||||||
"""Sorts the vertices in the graph so that vertices containing ChatInput or ChatOutput come first."""
|
"""Sorts the vertices in the graph so that vertices containing ChatInput or ChatOutput come first."""
|
||||||
|
|
||||||
def contains_interface_component(vertex):
|
def contains_interface_component(vertex):
|
||||||
return any(component.value in vertex for component in InterfaceComponentTypes)
|
return any(
|
||||||
|
component.value in vertex for component in InterfaceComponentTypes
|
||||||
|
)
|
||||||
|
|
||||||
# Sort each inner list so that vertices containing ChatInput or ChatOutput come first
|
# Sort each inner list so that vertices containing ChatInput or ChatOutput come first
|
||||||
sorted_vertices = [
|
sorted_vertices = [
|
||||||
|
|
@ -982,16 +1017,22 @@ class Graph:
|
||||||
]
|
]
|
||||||
return sorted_vertices
|
return sorted_vertices
|
||||||
|
|
||||||
def sort_by_avg_build_time(self, vertices_layers: List[List[str]]) -> List[List[str]]:
|
def sort_by_avg_build_time(
|
||||||
|
self, vertices_layers: List[List[str]]
|
||||||
|
) -> List[List[str]]:
|
||||||
"""Sorts the vertices in the graph so that vertices with the lowest average build time come first."""
|
"""Sorts the vertices in the graph so that vertices with the lowest average build time come first."""
|
||||||
|
|
||||||
def sort_layer_by_avg_build_time(vertices_ids: List[str]) -> List[str]:
|
def sort_layer_by_avg_build_time(vertices_ids: List[str]) -> List[str]:
|
||||||
"""Sorts the vertices in the graph so that vertices with the lowest average build time come first."""
|
"""Sorts the vertices in the graph so that vertices with the lowest average build time come first."""
|
||||||
if len(vertices_ids) == 1:
|
if len(vertices_ids) == 1:
|
||||||
return vertices_ids
|
return vertices_ids
|
||||||
vertices_ids.sort(key=lambda vertex_id: self.get_vertex(vertex_id).avg_build_time)
|
vertices_ids.sort(
|
||||||
|
key=lambda vertex_id: self.get_vertex(vertex_id).avg_build_time
|
||||||
|
)
|
||||||
|
|
||||||
return vertices_ids
|
return vertices_ids
|
||||||
|
|
||||||
sorted_vertices = [sort_layer_by_avg_build_time(layer) for layer in vertices_layers]
|
sorted_vertices = [
|
||||||
|
sort_layer_by_avg_build_time(layer) for layer in vertices_layers
|
||||||
|
]
|
||||||
return sorted_vertices
|
return sorted_vertices
|
||||||
|
|
|
||||||
|
|
@ -148,8 +148,8 @@ class CustomComponent(Component):
|
||||||
def update_build_config(
|
def update_build_config(
|
||||||
self,
|
self,
|
||||||
build_config: dotdict,
|
build_config: dotdict,
|
||||||
field_name: Optional[str],
|
|
||||||
field_value: Any,
|
field_value: Any,
|
||||||
|
field_name: Optional[str] = None,
|
||||||
):
|
):
|
||||||
build_config[field_name] = field_value
|
build_config[field_name] = field_value
|
||||||
return build_config
|
return build_config
|
||||||
|
|
@ -390,7 +390,7 @@ class CustomComponent(Component):
|
||||||
raise ValueError(f"Flow {flow_name} not found")
|
raise ValueError(f"Flow {flow_name} not found")
|
||||||
|
|
||||||
graph = await self.load_flow(flow_id, tweaks)
|
graph = await self.load_flow(flow_id, tweaks)
|
||||||
input_value_dict = {"input_value": input_value}
|
input_value_dict = [{"input_value": input_value}]
|
||||||
return await graph.run(input_value_dict, stream=False)
|
return await graph.run(input_value_dict, stream=False)
|
||||||
|
|
||||||
def list_flows(self, *, get_session: Optional[Callable] = None) -> List[Record]:
|
def list_flows(self, *, get_session: Optional[Callable] = None) -> List[Record]:
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,9 @@ def add_output_types(
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=400,
|
status_code=400,
|
||||||
detail={
|
detail={
|
||||||
"error": ("Invalid return type. Please check your code and try again."),
|
"error": (
|
||||||
|
"Invalid return type. Please check your code and try again."
|
||||||
|
),
|
||||||
"traceback": traceback.format_exc(),
|
"traceback": traceback.format_exc(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -75,14 +77,18 @@ def reorder_fields(frontend_node: CustomComponentFrontendNode, field_order: List
|
||||||
frontend_node.field_order = field_order
|
frontend_node.field_order = field_order
|
||||||
|
|
||||||
|
|
||||||
def add_base_classes(frontend_node: CustomComponentFrontendNode, return_types: List[str]):
|
def add_base_classes(
|
||||||
|
frontend_node: CustomComponentFrontendNode, return_types: List[str]
|
||||||
|
):
|
||||||
"""Add base classes to the frontend node"""
|
"""Add base classes to the frontend node"""
|
||||||
for return_type_instance in return_types:
|
for return_type_instance in return_types:
|
||||||
if return_type_instance is None:
|
if return_type_instance is None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=400,
|
status_code=400,
|
||||||
detail={
|
detail={
|
||||||
"error": ("Invalid return type. Please check your code and try again."),
|
"error": (
|
||||||
|
"Invalid return type. Please check your code and try again."
|
||||||
|
),
|
||||||
"traceback": traceback.format_exc(),
|
"traceback": traceback.format_exc(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -170,7 +176,9 @@ def add_new_custom_field(
|
||||||
)
|
)
|
||||||
|
|
||||||
if "name" in field_config:
|
if "name" in field_config:
|
||||||
warnings.warn("The 'name' key in field_config is used to build the object and can't be changed.")
|
warnings.warn(
|
||||||
|
"The 'name' key in field_config is used to build the object and can't be changed."
|
||||||
|
)
|
||||||
required = field_config.pop("required", field_required)
|
required = field_config.pop("required", field_required)
|
||||||
placeholder = field_config.pop("placeholder", "")
|
placeholder = field_config.pop("placeholder", "")
|
||||||
|
|
||||||
|
|
@ -269,7 +277,9 @@ def run_build_config(
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=400,
|
status_code=400,
|
||||||
detail={
|
detail={
|
||||||
"error": ("Invalid type convertion. Please check your code and try again."),
|
"error": (
|
||||||
|
"Invalid type convertion. Please check your code and try again."
|
||||||
|
),
|
||||||
"traceback": traceback.format_exc(),
|
"traceback": traceback.format_exc(),
|
||||||
},
|
},
|
||||||
) from exc
|
) from exc
|
||||||
|
|
@ -387,10 +397,16 @@ def build_custom_component_template(
|
||||||
|
|
||||||
add_extra_fields(frontend_node, field_config, entrypoint_args)
|
add_extra_fields(frontend_node, field_config, entrypoint_args)
|
||||||
|
|
||||||
frontend_node = add_code_field(frontend_node, custom_component.code, field_config.get("code", {}))
|
frontend_node = add_code_field(
|
||||||
|
frontend_node, custom_component.code, field_config.get("code", {})
|
||||||
|
)
|
||||||
|
|
||||||
add_base_classes(frontend_node, custom_component.get_function_entrypoint_return_type)
|
add_base_classes(
|
||||||
add_output_types(frontend_node, custom_component.get_function_entrypoint_return_type)
|
frontend_node, custom_component.get_function_entrypoint_return_type
|
||||||
|
)
|
||||||
|
add_output_types(
|
||||||
|
frontend_node, custom_component.get_function_entrypoint_return_type
|
||||||
|
)
|
||||||
|
|
||||||
reorder_fields(frontend_node, custom_instance._get_field_order())
|
reorder_fields(frontend_node, custom_instance._get_field_order())
|
||||||
|
|
||||||
|
|
@ -439,7 +455,9 @@ def build_custom_components(components_paths: List[str]):
|
||||||
custom_component_dict = build_custom_component_list_from_path(path_str)
|
custom_component_dict = build_custom_component_list_from_path(path_str)
|
||||||
if custom_component_dict:
|
if custom_component_dict:
|
||||||
category = next(iter(custom_component_dict))
|
category = next(iter(custom_component_dict))
|
||||||
logger.info(f"Loading {len(custom_component_dict[category])} component(s) from category {category}")
|
logger.info(
|
||||||
|
f"Loading {len(custom_component_dict[category])} component(s) from category {category}"
|
||||||
|
)
|
||||||
custom_components_from_file = merge_nested_dicts_with_renaming(
|
custom_components_from_file = merge_nested_dicts_with_renaming(
|
||||||
custom_components_from_file, custom_component_dict
|
custom_components_from_file, custom_component_dict
|
||||||
)
|
)
|
||||||
|
|
@ -467,7 +485,9 @@ def update_field_dict(
|
||||||
try:
|
try:
|
||||||
dd_build_config = dotdict(build_config)
|
dd_build_config = dotdict(build_config)
|
||||||
custom_component_instance.update_build_config(
|
custom_component_instance.update_build_config(
|
||||||
dd_build_config, update_field, update_field_value
|
build_config=dd_build_config,
|
||||||
|
field_value=update_field,
|
||||||
|
field_name=update_field_value,
|
||||||
)
|
)
|
||||||
build_config = dd_build_config
|
build_config = dd_build_config
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import asyncio
|
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from langflow.graph import Graph
|
from langflow.graph import Graph
|
||||||
from langflow.processing.process import fix_memory_inputs, process_tweaks
|
from langflow.processing.process import process_tweaks
|
||||||
|
|
||||||
|
|
||||||
def load_flow_from_json(flow: Union[Path, str, dict], tweaks: Optional[dict] = None, build=True):
|
def load_flow_from_json(
|
||||||
|
flow: Union[Path, str, dict], tweaks: Optional[dict] = None
|
||||||
|
) -> Graph:
|
||||||
"""
|
"""
|
||||||
Load flow from a JSON file or a JSON object.
|
Load flow from a JSON file or a JSON object.
|
||||||
|
|
||||||
|
|
@ -24,29 +25,13 @@ def load_flow_from_json(flow: Union[Path, str, dict], tweaks: Optional[dict] = N
|
||||||
elif isinstance(flow, dict):
|
elif isinstance(flow, dict):
|
||||||
flow_graph = flow
|
flow_graph = flow
|
||||||
else:
|
else:
|
||||||
raise TypeError("Input must be either a file path (str) or a JSON object (dict)")
|
raise TypeError(
|
||||||
|
"Input must be either a file path (str) or a JSON object (dict)"
|
||||||
|
)
|
||||||
|
|
||||||
graph_data = flow_graph["data"]
|
graph_data = flow_graph["data"]
|
||||||
if tweaks is not None:
|
if tweaks is not None:
|
||||||
graph_data = process_tweaks(graph_data, tweaks)
|
graph_data = process_tweaks(graph_data, tweaks)
|
||||||
nodes = graph_data["nodes"]
|
|
||||||
edges = graph_data["edges"]
|
|
||||||
graph = Graph(nodes, edges)
|
|
||||||
|
|
||||||
if build:
|
|
||||||
langchain_object = asyncio.run(graph.build())
|
|
||||||
|
|
||||||
if hasattr(langchain_object, "verbose"):
|
|
||||||
langchain_object.verbose = True
|
|
||||||
|
|
||||||
if hasattr(langchain_object, "return_intermediate_steps"):
|
|
||||||
# Deactivating until we have a frontend solution
|
|
||||||
# to display intermediate steps
|
|
||||||
langchain_object.return_intermediate_steps = False
|
|
||||||
|
|
||||||
fix_memory_inputs(langchain_object)
|
|
||||||
return langchain_object
|
|
||||||
|
|
||||||
return graph
|
|
||||||
|
|
||||||
|
graph = Graph.from_payload(graph_data)
|
||||||
return graph
|
return graph
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ async def run_graph(
|
||||||
if inputs is None:
|
if inputs is None:
|
||||||
inputs = [{}]
|
inputs = [{}]
|
||||||
|
|
||||||
outputs = await graph.run(
|
run_outputs = await graph.run(
|
||||||
inputs,
|
inputs,
|
||||||
outputs or [],
|
outputs or [],
|
||||||
stream=stream,
|
stream=stream,
|
||||||
|
|
@ -232,7 +232,7 @@ async def run_graph(
|
||||||
)
|
)
|
||||||
if session_id and session_service:
|
if session_id and session_service:
|
||||||
session_service.update_session(session_id, (graph, artifacts))
|
session_service.update_session(session_id, (graph, artifacts))
|
||||||
return outputs, session_id
|
return run_outputs, session_id
|
||||||
|
|
||||||
|
|
||||||
def validate_input(
|
def validate_input(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import TYPE_CHECKING, Any, Callable, Coroutine, Union
|
from typing import TYPE_CHECKING, Any, Callable, Coroutine
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
@ -74,11 +74,13 @@ class TaskService(Service):
|
||||||
result = await result
|
result = await result
|
||||||
return task.id, result
|
return task.id, result
|
||||||
|
|
||||||
async def launch_task(self, task_func: Callable[..., Any], *args: Any, **kwargs: Any) -> Any:
|
async def launch_task(
|
||||||
|
self, task_func: Callable[..., Any], *args: Any, **kwargs: Any
|
||||||
|
) -> Any:
|
||||||
logger.debug(f"Launching task {task_func} with args {args} and kwargs {kwargs}")
|
logger.debug(f"Launching task {task_func} with args {args} and kwargs {kwargs}")
|
||||||
logger.debug(f"Using backend {self.backend}")
|
logger.debug(f"Using backend {self.backend}")
|
||||||
task = self.backend.launch_task(task_func, *args, **kwargs)
|
task = self.backend.launch_task(task_func, *args, **kwargs)
|
||||||
return await task if isinstance(task, Coroutine) else task
|
return await task if isinstance(task, Coroutine) else task
|
||||||
|
|
||||||
def get_task(self, task_id: Union[int, str]) -> Any:
|
def get_task(self, task_id: str) -> Any:
|
||||||
return self.backend.get_task(task_id)
|
return self.backend.get_task(task_id)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue