Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: flow experimental components #3093

Merged
merged 22 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d7e8891
refactor(utils.py): simplify data processing logic in build_data_from…
ogabrielluiz Jul 29, 2024
23261e6
feat: set default output type to "chat" in run_flow function
ogabrielluiz Jul 29, 2024
38bb048
refactor(FlowTool.py): refactor FlowToolComponent class to inherit fr…
ogabrielluiz Jul 29, 2024
3385ea2
Merge branch 'main' into fix/flowtool
lucaseduoli Jul 30, 2024
a5ed845
Fixed Flow as Tool component
lucaseduoli Jul 30, 2024
d84d651
Fixed refresh button not appearing at the end
lucaseduoli Jul 30, 2024
c3bf680
Added way of connecting SecretStrInput to messages
lucaseduoli Jul 30, 2024
0078b43
Added real_time_refresh when field has button update too
lucaseduoli Jul 30, 2024
31d032f
Refactored SubFlow component
lucaseduoli Jul 30, 2024
33a5dc6
Fixed FlowTool to only output tool and removed async function def
lucaseduoli Jul 30, 2024
6037db5
Merge remote-tracking branch 'origin/main' into fix/flow_experimental…
lucaseduoli Jul 30, 2024
958a53a
fix: two statements in the same line
ogabrielluiz Jul 31, 2024
d1b39c9
Merge branch 'main' into fix/flow_experimental_component
lucaseduoli Jul 31, 2024
7b659e0
[autofix.ci] apply automated fixes
autofix-ci[bot] Jul 31, 2024
97b2c6e
Fixed lint issues
lucaseduoli Jul 31, 2024
1a7f32e
fixed dataobj with wrong name
lucaseduoli Jul 31, 2024
6245d5e
changed tweaks dict type
lucaseduoli Jul 31, 2024
e6aadd4
Fixed margin appearing in output too
lucaseduoli Jul 31, 2024
b0ac613
Fixed useless button that made styling worse on handlerendercomponent
lucaseduoli Jul 31, 2024
4196f1a
Merge branch 'main' into fix/flow_experimental_component
lucaseduoli Jul 31, 2024
3f3b483
fix: handle JSONDecodeError when loading starter projects
ogabrielluiz Jul 31, 2024
d55f2e7
Merge branch 'main' into fix/flow_experimental_component
lucaseduoli Jul 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/backend/base/langflow/base/flow_processing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ def build_data_from_result_data(result_data: ResultData, get_final_results_only:

if isinstance(result_data.results, dict):
for name, result in result_data.results.items():
dataobj: Data | Message | None = None
if isinstance(result, Message):
dataobj = result
else:
Expand Down
5 changes: 4 additions & 1 deletion src/backend/base/langflow/components/prototypes/FlowTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ def update_build_config(self, build_config: dotdict, field_value: Any, field_nam

inputs = [
DropdownInput(
name="flow_name", display_name="Flow Name", info="The name of the flow to run.", refresh_button=True
name="flow_name",
display_name="Flow Name",
info="The name of the flow to run.",
refresh_button=True
),
StrInput(
name="name",
Expand Down
117 changes: 56 additions & 61 deletions src/backend/base/langflow/components/prototypes/SubFlow.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
from typing import Any, List, Optional

from langflow.base.flow_processing.utils import build_data_from_result_data
from langflow.custom import CustomComponent
from langflow.custom import Component
from langflow.graph.graph.base import Graph
from langflow.graph.schema import RunOutputs
from langflow.graph.vertex.base import Vertex
from langflow.helpers.flow import get_flow_inputs
from langflow.schema import Data
from langflow.schema.dotdict import dotdict
from langflow.template.field.base import Input
from langflow.io import DropdownInput, Output
from langflow.schema import Data, dotdict

from loguru import logger


class SubFlowComponent(CustomComponent):
class SubFlowComponent(Component):
display_name = "Sub Flow"
description = (
"Dynamically Generates a Component from a Flow. The output is a list of data with keys 'result' and 'message'."
)
description = "Generates a Component from a Flow, with all of its inputs, and "
name = "SubFlow"
beta: bool = True
field_order = ["flow_name"]

def get_flow_names(self) -> List[str]:
flow_datas = self.list_flows()
return [flow_data.data["name"] for flow_data in flow_datas]
flow_data = self.list_flows()
return [flow_data.data["name"] for flow_data in flow_data]

def get_flow(self, flow_name: str) -> Optional[Data]:
flow_datas = self.list_flows()
Expand All @@ -33,12 +29,11 @@
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", "get_final_results_only"]:
if key not in [x.name for x in self.inputs] + ["code", "_type", "get_final_results_only"]:
del build_config[key]
if field_value is not None and field_name == "flow_name":
try:
Expand All @@ -55,62 +50,62 @@

return build_config

def add_inputs_to_build_config(self, inputs: List[Vertex], build_config: dotdict):
new_fields: list[Input] = []
for vertex in inputs:
field = Input(
display_name=vertex.display_name,
name=vertex.id,
info=vertex.description,
field_type="str",
value=None,
)
new_fields.append(field)
logger.debug(new_fields)
def add_inputs_to_build_config(self, inputs_vertex: List[Vertex], build_config: dotdict):
new_fields: list[dotdict] = []

for vertex in inputs_vertex:
new_vertex_inputs = []
field_template = vertex.data["node"]["template"]
for inp in field_template.keys():
if inp not in ["code", "_type"]:
field_template[inp]["display_name"] = vertex.display_name + " - " + field_template[inp]["display_name"]
field_template[inp]["name"] = vertex.id + "|" + inp
new_vertex_inputs.append(field_template[inp])
new_fields += new_vertex_inputs
for field in new_fields:
build_config[field.name] = field.to_dict()
build_config[field["name"]] = field
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.",
},
"get_final_results_only": {
"display_name": "Get Final Results Only",
"info": "If False, the output will contain all outputs from the flow.",
"advanced": True,
},
}

async def build(self, flow_name: str, get_final_results_only: bool = True, **kwargs) -> List[Data]:
tweaks = {key: {"input_value": value} for key, value in kwargs.items()}
run_outputs: List[Optional[RunOutputs]] = await self.run_flow(
inputs = [
DropdownInput(
name="flow_name",
display_name="Flow Name",
info="The name of the flow to run.",
options=[],
refresh_button=True,
real_time_refresh=True,
),
]

outputs = [
Output(
name="flow_outputs",
display_name="Flow Outputs",
method="generate_results"
)
]


async def generate_results(self) -> List[Data]:
tweaks = {}
for field in self._attributes.keys():
if field != "flow_name":
[node, name] = field.split("|")
if node not in tweaks.keys(): tweaks[node] = {}

Check failure on line 94 in src/backend/base/langflow/components/prototypes/SubFlow.py

View workflow job for this annotation

GitHub Actions / Ruff Style Check (3.12)

Ruff (E701)

src/backend/base/langflow/components/prototypes/SubFlow.py:94:45: E701 Multiple statements on one line (colon)
tweaks[node][name] = self._attributes[field]

run_outputs = await self.run_flow(
tweaks=tweaks,
flow_name=flow_name,
flow_name=self.flow_name,
output_type="all",
)
if not run_outputs:
return []
return {}
run_output = run_outputs[0]

data = []
if run_output is not None:
for output in run_output.outputs:
if output:
data.extend(build_data_from_result_data(output, get_final_results_only))

self.status = data
logger.debug(data)
data.extend(build_data_from_result_data(output))
return data
39 changes: 38 additions & 1 deletion src/backend/base/langflow/inputs/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,46 @@ class SecretStrInput(BaseInputMixin, DatabaseLoadMixin):

field_type: Optional[SerializableFieldTypes] = FieldTypes.PASSWORD
password: CoalesceBool = Field(default=True)
input_types: list[str] = []
input_types: list[str] = ["Message"]
load_from_db: CoalesceBool = True

@field_validator("value")
@classmethod
def validate_value(cls, v: Any, _info):
"""
Validates the given value and returns the processed value.
Args:
v (Any): The value to be validated.
_info: Additional information about the input.
Returns:
The processed value.
Raises:
ValueError: If the value is not of a valid type or if the input is missing a required key.
"""
value: str | AsyncIterator | Iterator | None = None
if isinstance(v, str):
value = v
elif isinstance(v, Message):
value = v.text
elif isinstance(v, Data):
if v.text_key in v.data:
value = v.data[v.text_key]
else:
keys = ", ".join(v.data.keys())
input_name = _info.data["name"]
raise ValueError(
f"The input to '{input_name}' must contain the key '{v.text_key}'."
f"You can set `text_key` to one of the following keys: {keys} or set the value using another Component."
)
elif isinstance(v, (AsyncIterator, Iterator)):
value = v
else:
raise ValueError(f"Invalid value type {type(v)}")
return value


class IntInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMixin):
"""
Expand Down
3 changes: 1 addition & 2 deletions src/frontend/src/CustomNodes/hooks/use-handle-new-value.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ const useHandleOnNewValue = ({
if (value !== undefined) parameter[key] = value;
});

const shouldUpdate =
parameter.real_time_refresh && !parameter.refresh_button;
const shouldUpdate = parameter.real_time_refresh;

const setNodeClass = (newNodeClass: APIClassType) => {
options?.setNodeClass && options.setNodeClass(newNodeClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function RefreshParameterComponent({
setErrorData,
);
return (
<div className="flex w-full items-center gap-2">
<div className="flex w-full items-center justify-between gap-2">
{children}
{templateData.refresh_button && (
<div className="shrink-0 flex-col">
Expand Down
Loading