Add SubFlowComponent to project
This commit is contained in:
parent
32e38e344e
commit
866299ca4d
1 changed files with 122 additions and 0 deletions
122
src/backend/langflow/components/experimental/SubFlow.py
Normal file
122
src/backend/langflow/components/experimental/SubFlow.py
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
from typing import Any, List, Optional, Text, Tuple
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langflow.graph.graph.base import Graph
|
||||||
|
from langflow.graph.schema import ResultData, RunOutputs
|
||||||
|
from langflow.schema import Record
|
||||||
|
from langflow.schema.dotdict import dotdict
|
||||||
|
from langflow.template.field.base import TemplateField
|
||||||
|
|
||||||
|
|
||||||
|
class SubFlowComponent(CustomComponent):
|
||||||
|
display_name = "SubFlow"
|
||||||
|
description = "Dynamically Generates a Component from a Flow. The output is a list of records with keys 'result' and 'message'."
|
||||||
|
beta: bool = True
|
||||||
|
field_order = ["flow_name"]
|
||||||
|
|
||||||
|
def get_flow_names(self) -> List[str]:
|
||||||
|
flow_records = self.list_flows()
|
||||||
|
return [flow_record.data["name"] for flow_record in flow_records]
|
||||||
|
|
||||||
|
def get_flow(self, flow_name: str) -> Optional[Text]:
|
||||||
|
flow_records = self.list_flows()
|
||||||
|
for flow_record in flow_records:
|
||||||
|
if flow_record.data["name"] == flow_name:
|
||||||
|
return flow_record
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
|
||||||
|
logger.debug(f"Updating build config with field value {field_value} and field name {field_name}")
|
||||||
|
if field_name == "flow_name":
|
||||||
|
build_config["flow_name"]["options"] = self.get_flow_names()
|
||||||
|
# Clean up the build config
|
||||||
|
for key in list(build_config.keys()):
|
||||||
|
if key not in self.field_order + ["code", "_type"]:
|
||||||
|
del build_config[key]
|
||||||
|
if field_value is not None and field_name == "flow_name":
|
||||||
|
try:
|
||||||
|
flow_record = self.get_flow(field_value)
|
||||||
|
if not flow_record:
|
||||||
|
raise ValueError(f"Flow {field_value} not found.")
|
||||||
|
graph = Graph.from_payload(flow_record.data["data"])
|
||||||
|
# Get all inputs from the graph
|
||||||
|
inputs = self.get_flow_inputs(graph)
|
||||||
|
# Add inputs to the build config
|
||||||
|
build_config = self.add_inputs_to_build_config(inputs, build_config)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error getting flow {field_value}: {str(e)}")
|
||||||
|
|
||||||
|
return build_config
|
||||||
|
|
||||||
|
def get_flow_inputs(self, graph: Graph) -> List[Record]:
|
||||||
|
inputs = []
|
||||||
|
for vertex in graph.vertices:
|
||||||
|
if vertex.is_input:
|
||||||
|
inputs.append((vertex.id, vertex.display_name, vertex.description))
|
||||||
|
logger.debug(inputs)
|
||||||
|
return inputs
|
||||||
|
|
||||||
|
def add_inputs_to_build_config(self, inputs: List[Tuple], build_config: dotdict):
|
||||||
|
new_fields: list[TemplateField] = []
|
||||||
|
for input_id, input_display_name, input_description in inputs:
|
||||||
|
field = TemplateField(
|
||||||
|
display_name=input_display_name,
|
||||||
|
name=input_id,
|
||||||
|
info=input_description,
|
||||||
|
field_type="str",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
new_fields.append(field)
|
||||||
|
logger.debug(new_fields)
|
||||||
|
for field in new_fields:
|
||||||
|
build_config[field.name] = field.to_dict()
|
||||||
|
return build_config
|
||||||
|
|
||||||
|
def build_config(self):
|
||||||
|
return {
|
||||||
|
"input_value": {
|
||||||
|
"display_name": "Input Value",
|
||||||
|
"multiline": True,
|
||||||
|
},
|
||||||
|
"flow_name": {
|
||||||
|
"display_name": "Flow Name",
|
||||||
|
"info": "The name of the flow to run.",
|
||||||
|
"options": [],
|
||||||
|
"real_time_refresh": True,
|
||||||
|
"refresh_button": True,
|
||||||
|
},
|
||||||
|
"tweaks": {
|
||||||
|
"display_name": "Tweaks",
|
||||||
|
"info": "Tweaks to apply to the flow.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build_records_from_result_data(self, result_data: ResultData) -> List[Record]:
|
||||||
|
messages = result_data.messages
|
||||||
|
if not messages:
|
||||||
|
return []
|
||||||
|
records = []
|
||||||
|
for message in messages:
|
||||||
|
message_dict = message if isinstance(message, dict) else message.model_dump()
|
||||||
|
record = Record(data={"result": result_data.model_dump(), "message": message_dict.get("message", "")})
|
||||||
|
records.append(record)
|
||||||
|
return records
|
||||||
|
|
||||||
|
async def build(self, flow_name: str, **kwargs) -> List[Record]:
|
||||||
|
tweaks = {key: {"input_value": value} for key, value in kwargs.items()}
|
||||||
|
run_outputs: List[Optional[RunOutputs]] = await self.run_flow(
|
||||||
|
tweaks=tweaks,
|
||||||
|
flow_name=flow_name,
|
||||||
|
)
|
||||||
|
run_output = run_outputs[0]
|
||||||
|
|
||||||
|
records = []
|
||||||
|
for output in run_output.outputs:
|
||||||
|
if output:
|
||||||
|
records.extend(self.build_records_from_result_data(output))
|
||||||
|
|
||||||
|
self.status = records
|
||||||
|
logger.debug(records)
|
||||||
|
return records
|
||||||
Loading…
Add table
Add a link
Reference in a new issue