fix: General Fixes and Improvements from v1.0.19.2 Fixes Branch (#4411)
* fix: update assistants client import (#4150) * remove unnecessary patch * remove unnecessary patch * compatible release operator * chore: add opensearch-py dependency (#4134) Add opensearch-py dependency to pyproject.toml * patch version * lock * lock some packages to speed up pip install * langflow-base version * fix: fix retrieverTool component (#4201) ♻️ (RetrieverTool.py): refactor build method signature to accept additional keyword arguments for future extensibility * Fixed save modal not exiting * fix: object has no attribute 'set_event_manager' (#4200) * 🐛 (base.py): fix AttributeError by checking if custom_component has set_event_manager method before calling it * 📝 (base.py): Import Component from langflow.custom to improve code readability and maintainability ♻️ (base.py): Refactor code to use isinstance() method for checking if custom_component is an instance of Component * Refactor: Eliminate Global Variables for Improved Code Maintainability_fix_release (#4208) Refactor: Eliminate Global Variables for Improved Code Maintainability - Replaced global variables with local variables or class attributes. - Enhanced code readability and reduced potential side effects. * fix: Update example (#4204) update example * fix: avoids error NameError: name 'MAX_NUMBER_OF_FIELDS' is not defin… (#4203) fix: avoids error NameError: name 'MAX_NUMBER_OF_FIELDS' is not defined and fixes build method Co-authored-by: Edwin Jose <edwin.jose@datastax.com> * fix: unexpected keyword argument 'code' -> SQLExecutor and SQLDatabase (#4230) 🔧 (SQLDatabase.py): update build method signature to accept additional keyword arguments for future extensibility 🔧 (SQLExecutor.py): update method signature to accept additional keyword arguments for future extensibility * lock httptools to 0.6.4 * Move ChatInput import to within flow_component fixture in conftest.py * Simplify error message formatting in test cases for data components * Add readme to dockerfile * build: dockerfile with entrypoint (#4062) Adds a dockerfile with an entrypoint for use with Datastax Langflow * fixes the leading v for checking out commits correctly * fixes on more version checkout for docker build * ✨ (authContext.tsx): Add functionality to fetch global variables on authentication 🔧 (api.tsx): Replace universal-cookie import with react-cookie for consistency 🔧 (authStore.ts): Replace universal-cookie import with react-cookie for consistency 🔧 (use-get-global-variables.ts): Add check to only fetch global variables if user is authenticated ✨ (use-get-mutation-global-variables.ts): Add mutation function to fetch and update global variables 🔧 (authStore.ts): Replace universal-cookie import with react-cookie for consistency * [autofix.ci] apply automated fixes * revert changes to workflows * upgrade lockfile * update pyproject versions * update lockfile again * ⬆️ (pyproject.toml): upgrade langflow-base dependency to version 0.0.99 * ⬆️ (pyproject.toml): downgrade version from 0.0.99 to 0.0.97 to align with project requirements and dependencies. * ⬆️ (pyproject.toml): downgrade langflow-base dependency version from 0.0.99 to 0.0.97 to resolve compatibility issues * ⬆️ (uv.lock): downgrade langchain-core package version from 0.3.15 to 0.3.12 to resolve compatibility issues with dependencies * ⬆️ (pyproject.toml): upgrade langflow-base dependency to version 0.0.99 to utilize the latest features and improvements --------- Co-authored-by: Sebastián Estévez <estevezsebastian@gmail.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> Co-authored-by: Lucas Oliveira <lucas.edu.oli@hotmail.com> Co-authored-by: Edwin Jose <edwin.jose@datastax.com> Co-authored-by: anovazzi1 <otavio2204@gmail.com> Co-authored-by: João <38133825+joaoguilhermeS@users.noreply.github.com> Co-authored-by: Jordan Frazier <jordan.frazier@datastax.com> Co-authored-by: Jordan Frazier <122494242+jordanrfrazier@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
ae7d037fe1
commit
73df2182de
13 changed files with 1228 additions and 1559 deletions
|
|
@ -12,7 +12,7 @@ packages = ["src/backend/langflow"]
|
|||
|
||||
[project]
|
||||
name = "langflow"
|
||||
version = "1.0.19"
|
||||
version = "1.0.19.post2"
|
||||
description = "A Python package with a built-in web application"
|
||||
requires-python = ">=3.10,<3.13"
|
||||
license = "MIT"
|
||||
|
|
@ -31,7 +31,7 @@ maintainers = [
|
|||
|
||||
# Define your main dependencies here
|
||||
dependencies = [
|
||||
"langflow-base==0.0.97",
|
||||
"langflow-base==0.0.99",
|
||||
"beautifulsoup4>=4.12.2",
|
||||
"google-search-results>=2.4.1",
|
||||
"google-api-python-client>=2.130.0",
|
||||
|
|
@ -68,6 +68,8 @@ dependencies = [
|
|||
"litellm>=1.44.0",
|
||||
"chromadb>=0.4",
|
||||
"zep-python>=2.0.0",
|
||||
"langchain-groq>=0.1.9",
|
||||
"langchain-pinecone>=0.1.3",
|
||||
"youtube-transcript-api>=0.6.2",
|
||||
"markdown>=3.7",
|
||||
"upstash-vector>=0.5.0",
|
||||
|
|
@ -75,6 +77,8 @@ dependencies = [
|
|||
"kubernetes>=30.1.0",
|
||||
"firecrawl-py>=0.0.16",
|
||||
"json-repair>=0.25.2",
|
||||
"langchain-google-calendar-tools>=0.0.1",
|
||||
"langchain-milvus>=0.1.1",
|
||||
"langwatch==0.1.16",
|
||||
"langsmith~=0.1.136",
|
||||
"yfinance>=0.2.40",
|
||||
|
|
@ -107,6 +111,7 @@ dependencies = [
|
|||
"langchain-milvus>=0.1.1",
|
||||
"langchain-google-community~=2.0.1",
|
||||
"langchain-elasticsearch>=0.2.0",
|
||||
"opensearch-py>=2.7.1",
|
||||
"langchain-ollama>=0.2.0",
|
||||
"pymupdf~=1.24.13",
|
||||
"sqlalchemy[aiosqlite,postgresql_psycopg2binary,postgresql_psycopgbinary]>=2.0.36"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
from typing import Any
|
||||
|
||||
from astra_assistants import patch
|
||||
from openai import OpenAI
|
||||
from openai.lib.streaming import AssistantEventHandler
|
||||
|
||||
from langflow.base.astra_assistants.util import get_patched_openai_client
|
||||
|
|
@ -63,8 +61,6 @@ class AssistantsRun(ComponentWithCache):
|
|||
outputs = [Output(display_name="Assistant Response", name="assistant_response", method="process_inputs")]
|
||||
|
||||
def process_inputs(self) -> Message:
|
||||
patch(OpenAI())
|
||||
|
||||
text = ""
|
||||
|
||||
if self.thread_id is None:
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ from langflow.io import Output
|
|||
from langflow.schema import Data
|
||||
from langflow.schema.dotdict import dotdict
|
||||
|
||||
MAX_NUMBER_OF_FIELDS = 15
|
||||
|
||||
|
||||
class CreateDataComponent(Component):
|
||||
display_name: str = "Create Data"
|
||||
description: str = "Dynamically create a Data with a specified number of fields."
|
||||
name: str = "CreateData"
|
||||
MAX_FIELDS = 15 # Define a constant for maximum number of fields
|
||||
|
||||
inputs = [
|
||||
IntInput(
|
||||
|
|
@ -22,7 +21,7 @@ class CreateDataComponent(Component):
|
|||
info="Number of fields to be added to the record.",
|
||||
real_time_refresh=True,
|
||||
value=1,
|
||||
range_spec=RangeSpec(min=1, max=15, step=1, step_type="int"),
|
||||
range_spec=RangeSpec(min=1, max=MAX_FIELDS, step=1, step_type="int"),
|
||||
),
|
||||
MessageTextInput(
|
||||
name="text_key",
|
||||
|
|
@ -50,10 +49,11 @@ class CreateDataComponent(Component):
|
|||
except ValueError:
|
||||
return build_config
|
||||
existing_fields = {}
|
||||
if field_value_int > MAX_NUMBER_OF_FIELDS:
|
||||
build_config["number_of_fields"]["value"] = MAX_NUMBER_OF_FIELDS
|
||||
if field_value_int > self.MAX_FIELDS:
|
||||
build_config["number_of_fields"]["value"] = self.MAX_FIELDS
|
||||
msg = (
|
||||
f"Number of fields cannot exceed {MAX_NUMBER_OF_FIELDS}. Try using a Component to combine two Data."
|
||||
f"Number of fields cannot exceed {self.MAX_FIELDS}. "
|
||||
"Please adjust the number of fields to be within the allowed limit."
|
||||
)
|
||||
raise ValueError(msg)
|
||||
if len(build_config) > len(default_keys):
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ class SQLExecutorComponent(CustomComponent):
|
|||
include_columns: bool = False,
|
||||
passthrough: bool = False,
|
||||
add_error: bool = False,
|
||||
**kwargs,
|
||||
) -> Text:
|
||||
_ = kwargs
|
||||
error = None
|
||||
try:
|
||||
database = SQLDatabase.from_uri(database_url)
|
||||
|
|
|
|||
|
|
@ -2,25 +2,30 @@ from typing import Any
|
|||
|
||||
from langflow.custom import Component
|
||||
from langflow.field_typing.range_spec import RangeSpec
|
||||
from langflow.inputs.inputs import BoolInput, DataInput, DictInput, IntInput, MessageTextInput
|
||||
from langflow.inputs.inputs import (
|
||||
BoolInput,
|
||||
DataInput,
|
||||
DictInput,
|
||||
IntInput,
|
||||
MessageTextInput,
|
||||
)
|
||||
from langflow.io import Output
|
||||
from langflow.schema import Data
|
||||
from langflow.schema.dotdict import dotdict
|
||||
|
||||
MAX_NUMBER_OF_FIELDS = 15
|
||||
|
||||
|
||||
class UpdateDataComponent(Component):
|
||||
display_name: str = "Update data"
|
||||
description: str = "Dynamically update or append data with the specified fields."
|
||||
name: str = "UpdateData"
|
||||
MAX_FIELDS = 15 # Define a constant for maximum number of fields
|
||||
|
||||
inputs = [
|
||||
DataInput(
|
||||
name="old_data",
|
||||
display_name="Data",
|
||||
info="The record to update.",
|
||||
is_list=False,
|
||||
is_list=True, # Changed to True to handle list of Data objects
|
||||
),
|
||||
IntInput(
|
||||
name="number_of_fields",
|
||||
|
|
@ -28,7 +33,7 @@ class UpdateDataComponent(Component):
|
|||
info="Number of fields to be added to the record.",
|
||||
real_time_refresh=True,
|
||||
value=0,
|
||||
range_spec=RangeSpec(min=1, max=15, step=1, step_type="int"),
|
||||
range_spec=RangeSpec(min=1, max=MAX_FIELDS, step=1, step_type="int"),
|
||||
),
|
||||
MessageTextInput(
|
||||
name="text_key",
|
||||
|
|
@ -49,24 +54,37 @@ class UpdateDataComponent(Component):
|
|||
]
|
||||
|
||||
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
|
||||
"""Update the build configuration when the number of fields changes.
|
||||
|
||||
Args:
|
||||
build_config (dotdict): The current build configuration.
|
||||
field_value (Any): The new value for the field.
|
||||
field_name (Optional[str]): The name of the field being updated.
|
||||
"""
|
||||
if field_name == "number_of_fields":
|
||||
default_keys = ["code", "_type", "number_of_fields", "text_key", "old_data", "text_key_validator"]
|
||||
default_keys = {
|
||||
"code",
|
||||
"_type",
|
||||
"number_of_fields",
|
||||
"text_key",
|
||||
"old_data",
|
||||
"text_key_validator",
|
||||
}
|
||||
try:
|
||||
field_value_int = int(field_value)
|
||||
except ValueError:
|
||||
return build_config
|
||||
existing_fields = {}
|
||||
if field_value_int > MAX_NUMBER_OF_FIELDS:
|
||||
build_config["number_of_fields"]["value"] = MAX_NUMBER_OF_FIELDS
|
||||
msg = (
|
||||
f"Number of fields cannot exceed {MAX_NUMBER_OF_FIELDS}. Try using a Component to combine two Data."
|
||||
)
|
||||
|
||||
if field_value_int > self.MAX_FIELDS:
|
||||
build_config["number_of_fields"]["value"] = self.MAX_FIELDS
|
||||
msg = f"Number of fields cannot exceed {self.MAX_FIELDS}. " "Try using a Component to combine two Data."
|
||||
raise ValueError(msg)
|
||||
if len(build_config) > len(default_keys):
|
||||
# back up the existing template fields
|
||||
for key in build_config.copy():
|
||||
if key not in default_keys:
|
||||
existing_fields[key] = build_config.pop(key)
|
||||
|
||||
existing_fields = {}
|
||||
# Back up the existing template fields
|
||||
for key in list(build_config.keys()):
|
||||
if key not in default_keys:
|
||||
existing_fields[key] = build_config.pop(key)
|
||||
|
||||
for i in range(1, field_value_int + 1):
|
||||
key = f"field_{i}_key"
|
||||
|
|
@ -85,30 +103,55 @@ class UpdateDataComponent(Component):
|
|||
build_config["number_of_fields"]["value"] = field_value_int
|
||||
return build_config
|
||||
|
||||
async def build_data(self) -> Data:
|
||||
async def build_data(self) -> Data | list[Data]:
|
||||
"""Build the updated data by combining the old data with new fields."""
|
||||
new_data = self.get_data()
|
||||
self.old_data.data.update(new_data)
|
||||
if self.text_key:
|
||||
self.old_data.text_key = self.text_key
|
||||
self.status = self.old_data
|
||||
self.validate_text_key(self.old_data)
|
||||
return self.old_data
|
||||
if isinstance(self.old_data, list):
|
||||
for data_item in self.old_data:
|
||||
if not isinstance(data_item, Data):
|
||||
continue # Skip invalid items
|
||||
data_item.data.update(new_data)
|
||||
if self.text_key:
|
||||
data_item.text_key = self.text_key
|
||||
self.validate_text_key(data_item)
|
||||
self.status = self.old_data
|
||||
return self.old_data # Returns List[Data]
|
||||
if isinstance(self.old_data, Data):
|
||||
self.old_data.data.update(new_data)
|
||||
if self.text_key:
|
||||
self.old_data.text_key = self.text_key
|
||||
self.status = self.old_data
|
||||
self.validate_text_key(self.old_data)
|
||||
return self.old_data # Returns Data
|
||||
msg = "old_data is not a Data object or list of Data objects."
|
||||
raise ValueError(msg)
|
||||
|
||||
def get_data(self):
|
||||
"""Function to get the Data from the attributes."""
|
||||
data = {}
|
||||
for value_dict in self._attributes.values():
|
||||
if isinstance(value_dict, dict):
|
||||
# Check if the value of the value_dict is a Data
|
||||
_value_dict = {
|
||||
key: value.get_text() if isinstance(value, Data) else value for key, value in value_dict.items()
|
||||
}
|
||||
data.update(_value_dict)
|
||||
default_keys = {
|
||||
"code",
|
||||
"_type",
|
||||
"number_of_fields",
|
||||
"text_key",
|
||||
"old_data",
|
||||
"text_key_validator",
|
||||
}
|
||||
for attr_name, attr_value in self._attributes.items():
|
||||
if attr_name in default_keys:
|
||||
continue # Skip default attributes
|
||||
if isinstance(attr_value, dict):
|
||||
for key, value in attr_value.items():
|
||||
data[key] = value.get_text() if isinstance(value, Data) else value
|
||||
elif isinstance(attr_value, Data):
|
||||
data[attr_name] = attr_value.get_text()
|
||||
else:
|
||||
data[attr_name] = attr_value
|
||||
return data
|
||||
|
||||
def validate_text_key(self, data: Data) -> None:
|
||||
"""This function validates that the Text Key is one of the keys in the Data."""
|
||||
data_keys = data.data.keys()
|
||||
if self.text_key not in data_keys and self.text_key != "":
|
||||
msg = f"Text Key: {self.text_key} not found in the Data keys: {','.join(data_keys)}"
|
||||
if self.text_key and self.text_key not in data_keys:
|
||||
msg = f"Text Key: '{self.text_key}' not found in the Data keys: " f"{', '.join(data_keys)}"
|
||||
raise ValueError(msg)
|
||||
|
|
|
|||
|
|
@ -21,12 +21,8 @@ class RetrieverToolComponent(CustomComponent):
|
|||
"description": {"display_name": "Description", "info": "Description of the tool"},
|
||||
}
|
||||
|
||||
def build(
|
||||
self,
|
||||
retriever: BaseRetriever,
|
||||
name: str,
|
||||
description: str,
|
||||
) -> Tool:
|
||||
def build(self, retriever: BaseRetriever, name: str, description: str, **kwargs) -> Tool:
|
||||
_ = kwargs
|
||||
return create_retriever_tool(
|
||||
retriever=retriever,
|
||||
name=name,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"data": {
|
||||
"sourceHandle": {
|
||||
"dataType": "URL",
|
||||
"id": "URL-46k0m",
|
||||
"id": "URL-v3FkJ",
|
||||
"name": "data",
|
||||
"output_types": [
|
||||
"Data"
|
||||
|
|
@ -14,25 +14,25 @@
|
|||
},
|
||||
"targetHandle": {
|
||||
"fieldName": "data",
|
||||
"id": "ParseData-jUQRS",
|
||||
"id": "ParseData-qffHj",
|
||||
"inputTypes": [
|
||||
"Data"
|
||||
],
|
||||
"type": "other"
|
||||
}
|
||||
},
|
||||
"id": "reactflow__edge-URL-46k0m{œdataTypeœ:œURLœ,œidœ:œURL-46k0mœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-ParseData-jUQRS{œfieldNameœ:œdataœ,œidœ:œParseData-jUQRSœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
|
||||
"source": "URL-46k0m",
|
||||
"sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-46k0mœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}",
|
||||
"target": "ParseData-jUQRS",
|
||||
"targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-jUQRSœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
|
||||
"id": "reactflow__edge-URL-v3FkJ{œdataTypeœ:œURLœ,œidœ:œURL-v3FkJœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-ParseData-qffHj{œfieldNameœ:œdataœ,œidœ:œParseData-qffHjœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
|
||||
"source": "URL-v3FkJ",
|
||||
"sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-v3FkJœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}",
|
||||
"target": "ParseData-qffHj",
|
||||
"targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-qffHjœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
|
||||
},
|
||||
{
|
||||
"className": "",
|
||||
"data": {
|
||||
"sourceHandle": {
|
||||
"dataType": "ParseData",
|
||||
"id": "ParseData-jUQRS",
|
||||
"id": "ParseData-qffHj",
|
||||
"name": "text",
|
||||
"output_types": [
|
||||
"Message"
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
},
|
||||
"targetHandle": {
|
||||
"fieldName": "references",
|
||||
"id": "Prompt-Pf4QQ",
|
||||
"id": "Prompt-ztjwI",
|
||||
"inputTypes": [
|
||||
"Message",
|
||||
"Text"
|
||||
|
|
@ -48,18 +48,18 @@
|
|||
"type": "str"
|
||||
}
|
||||
},
|
||||
"id": "reactflow__edge-ParseData-jUQRS{œdataTypeœ:œParseDataœ,œidœ:œParseData-jUQRSœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-Pf4QQ{œfieldNameœ:œreferencesœ,œidœ:œPrompt-Pf4QQœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"source": "ParseData-jUQRS",
|
||||
"sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-jUQRSœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
|
||||
"target": "Prompt-Pf4QQ",
|
||||
"targetHandle": "{œfieldNameœ: œreferencesœ, œidœ: œPrompt-Pf4QQœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
|
||||
"id": "reactflow__edge-ParseData-qffHj{œdataTypeœ:œParseDataœ,œidœ:œParseData-qffHjœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-ztjwI{œfieldNameœ:œreferencesœ,œidœ:œPrompt-ztjwIœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"source": "ParseData-qffHj",
|
||||
"sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-qffHjœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
|
||||
"target": "Prompt-ztjwI",
|
||||
"targetHandle": "{œfieldNameœ: œreferencesœ, œidœ: œPrompt-ztjwIœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
|
||||
},
|
||||
{
|
||||
"className": "",
|
||||
"data": {
|
||||
"sourceHandle": {
|
||||
"dataType": "TextInput",
|
||||
"id": "TextInput-slCbp",
|
||||
"id": "TextInput-A7goL",
|
||||
"name": "text",
|
||||
"output_types": [
|
||||
"Message"
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
},
|
||||
"targetHandle": {
|
||||
"fieldName": "instructions",
|
||||
"id": "Prompt-Pf4QQ",
|
||||
"id": "Prompt-ztjwI",
|
||||
"inputTypes": [
|
||||
"Message",
|
||||
"Text"
|
||||
|
|
@ -75,18 +75,18 @@
|
|||
"type": "str"
|
||||
}
|
||||
},
|
||||
"id": "reactflow__edge-TextInput-slCbp{œdataTypeœ:œTextInputœ,œidœ:œTextInput-slCbpœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-Pf4QQ{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-Pf4QQœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"source": "TextInput-slCbp",
|
||||
"sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-slCbpœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
|
||||
"target": "Prompt-Pf4QQ",
|
||||
"targetHandle": "{œfieldNameœ: œinstructionsœ, œidœ: œPrompt-Pf4QQœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
|
||||
"id": "reactflow__edge-TextInput-A7goL{œdataTypeœ:œTextInputœ,œidœ:œTextInput-A7goLœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-ztjwI{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-ztjwIœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
|
||||
"source": "TextInput-A7goL",
|
||||
"sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-A7goLœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
|
||||
"target": "Prompt-ztjwI",
|
||||
"targetHandle": "{œfieldNameœ: œinstructionsœ, œidœ: œPrompt-ztjwIœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
|
||||
},
|
||||
{
|
||||
"className": "",
|
||||
"data": {
|
||||
"sourceHandle": {
|
||||
"dataType": "Prompt",
|
||||
"id": "Prompt-Pf4QQ",
|
||||
"id": "Prompt-ztjwI",
|
||||
"name": "prompt",
|
||||
"output_types": [
|
||||
"Message"
|
||||
|
|
@ -94,25 +94,25 @@
|
|||
},
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "OpenAIModel-o0Gr0",
|
||||
"id": "OpenAIModel-Y3GUP",
|
||||
"inputTypes": [
|
||||
"Message"
|
||||
],
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
"id": "reactflow__edge-Prompt-Pf4QQ{œdataTypeœ:œPromptœ,œidœ:œPrompt-Pf4QQœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-o0Gr0{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-o0Gr0œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
|
||||
"source": "Prompt-Pf4QQ",
|
||||
"sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-Pf4QQœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
|
||||
"target": "OpenAIModel-o0Gr0",
|
||||
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-o0Gr0œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
|
||||
"id": "reactflow__edge-Prompt-ztjwI{œdataTypeœ:œPromptœ,œidœ:œPrompt-ztjwIœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-Y3GUP{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Y3GUPœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
|
||||
"source": "Prompt-ztjwI",
|
||||
"sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-ztjwIœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
|
||||
"target": "OpenAIModel-Y3GUP",
|
||||
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-Y3GUPœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
|
||||
},
|
||||
{
|
||||
"className": "",
|
||||
"data": {
|
||||
"sourceHandle": {
|
||||
"dataType": "OpenAIModel",
|
||||
"id": "OpenAIModel-o0Gr0",
|
||||
"id": "OpenAIModel-Y3GUP",
|
||||
"name": "text_output",
|
||||
"output_types": [
|
||||
"Message"
|
||||
|
|
@ -120,18 +120,18 @@
|
|||
},
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatOutput-eIVde",
|
||||
"id": "ChatOutput-Y7FC3",
|
||||
"inputTypes": [
|
||||
"Message"
|
||||
],
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
"id": "reactflow__edge-OpenAIModel-o0Gr0{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-o0Gr0œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-eIVde{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-eIVdeœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
|
||||
"source": "OpenAIModel-o0Gr0",
|
||||
"sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-o0Gr0œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
|
||||
"target": "ChatOutput-eIVde",
|
||||
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-eIVdeœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
|
||||
"id": "reactflow__edge-OpenAIModel-Y3GUP{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Y3GUPœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Y7FC3{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Y7FC3œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
|
||||
"source": "OpenAIModel-Y3GUP",
|
||||
"sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-Y3GUPœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
|
||||
"target": "ChatOutput-Y7FC3",
|
||||
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Y7FC3œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
"data": {
|
||||
"description": "Fetch content from one or more URLs.",
|
||||
"display_name": "URL",
|
||||
"id": "URL-46k0m",
|
||||
"id": "URL-v3FkJ",
|
||||
"node": {
|
||||
"base_classes": [
|
||||
"Data"
|
||||
|
|
@ -252,8 +252,8 @@
|
|||
"type": "URL"
|
||||
},
|
||||
"dragging": false,
|
||||
"height": 397,
|
||||
"id": "URL-46k0m",
|
||||
"height": 465,
|
||||
"id": "URL-v3FkJ",
|
||||
"position": {
|
||||
"x": 220.79156431407534,
|
||||
"y": 498.8186168722667
|
||||
|
|
@ -270,7 +270,7 @@
|
|||
"data": {
|
||||
"description": "Convert Data into plain text following a specified template.",
|
||||
"display_name": "Parse Data",
|
||||
"id": "ParseData-jUQRS",
|
||||
"id": "ParseData-qffHj",
|
||||
"node": {
|
||||
"base_classes": [
|
||||
"Message"
|
||||
|
|
@ -387,8 +387,8 @@
|
|||
"type": "ParseData"
|
||||
},
|
||||
"dragging": false,
|
||||
"height": 378,
|
||||
"id": "ParseData-jUQRS",
|
||||
"height": 353,
|
||||
"id": "ParseData-qffHj",
|
||||
"position": {
|
||||
"x": 754.3607306709101,
|
||||
"y": 736.8516961537598
|
||||
|
|
@ -405,7 +405,7 @@
|
|||
"data": {
|
||||
"description": "Create a prompt template with dynamic variables.",
|
||||
"display_name": "Prompt",
|
||||
"id": "Prompt-Pf4QQ",
|
||||
"id": "Prompt-ztjwI",
|
||||
"node": {
|
||||
"base_classes": [
|
||||
"Message"
|
||||
|
|
@ -533,8 +533,8 @@
|
|||
"type": "Prompt"
|
||||
},
|
||||
"dragging": false,
|
||||
"height": 502,
|
||||
"id": "Prompt-Pf4QQ",
|
||||
"height": 477,
|
||||
"id": "Prompt-ztjwI",
|
||||
"position": {
|
||||
"x": 1368.0633591447076,
|
||||
"y": 467.19448061224284
|
||||
|
|
@ -551,7 +551,7 @@
|
|||
"data": {
|
||||
"description": "Get text inputs from the Playground.",
|
||||
"display_name": "Instructions",
|
||||
"id": "TextInput-slCbp",
|
||||
"id": "TextInput-A7goL",
|
||||
"node": {
|
||||
"base_classes": [
|
||||
"Message"
|
||||
|
|
@ -568,6 +568,7 @@
|
|||
],
|
||||
"frozen": false,
|
||||
"icon": "type",
|
||||
"metadata": {},
|
||||
"output_types": [],
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -601,7 +602,7 @@
|
|||
"show": true,
|
||||
"title_case": false,
|
||||
"type": "code",
|
||||
"value": "from langflow.base.io.text import TextComponent\nfrom langflow.io import MultilineInput, Output\nfrom langflow.schema.message import Message\n\n\nclass TextInputComponent(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n name = \"TextInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Text to be passed as input.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"text_response\"),\n ]\n\n def text_response(self) -> Message:\n message = Message(\n text=self.input_value,\n )\n return message\n"
|
||||
"value": "from langflow.base.io.text import TextComponent\nfrom langflow.io import MultilineInput, Output\nfrom langflow.schema.message import Message\n\n\nclass TextInputComponent(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Playground.\"\n icon = \"type\"\n name = \"TextInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Text to be passed as input.\",\n ),\n ]\n outputs = [\n Output(display_name=\"Text\", name=\"text\", method=\"text_response\"),\n ]\n\n def text_response(self) -> Message:\n return Message(\n text=self.input_value,\n )\n"
|
||||
},
|
||||
"input_value": {
|
||||
"_input_type": "MultilineInput",
|
||||
|
|
@ -630,8 +631,8 @@
|
|||
"type": "TextInput"
|
||||
},
|
||||
"dragging": false,
|
||||
"height": 302,
|
||||
"id": "TextInput-slCbp",
|
||||
"height": 289,
|
||||
"id": "TextInput-A7goL",
|
||||
"position": {
|
||||
"x": 743.7338453293725,
|
||||
"y": 301.58775454952183
|
||||
|
|
@ -648,7 +649,7 @@
|
|||
"data": {
|
||||
"description": "Display a chat message in the Playground.",
|
||||
"display_name": "Chat Output",
|
||||
"id": "ChatOutput-eIVde",
|
||||
"id": "ChatOutput-Y7FC3",
|
||||
"node": {
|
||||
"base_classes": [
|
||||
"Message"
|
||||
|
|
@ -889,8 +890,8 @@
|
|||
"type": "ChatOutput"
|
||||
},
|
||||
"dragging": false,
|
||||
"height": 302,
|
||||
"id": "ChatOutput-eIVde",
|
||||
"height": 289,
|
||||
"id": "ChatOutput-Y7FC3",
|
||||
"position": {
|
||||
"x": 2449.3489426461606,
|
||||
"y": 571.2449700910389
|
||||
|
|
@ -907,7 +908,7 @@
|
|||
"data": {
|
||||
"description": "Generates text using OpenAI LLMs.",
|
||||
"display_name": "OpenAI",
|
||||
"id": "OpenAIModel-o0Gr0",
|
||||
"id": "OpenAIModel-Y3GUP",
|
||||
"node": {
|
||||
"base_classes": [
|
||||
"LanguageModel",
|
||||
|
|
@ -1223,8 +1224,8 @@
|
|||
"type": "OpenAIModel"
|
||||
},
|
||||
"dragging": false,
|
||||
"height": 605,
|
||||
"id": "OpenAIModel-o0Gr0",
|
||||
"height": 587,
|
||||
"id": "OpenAIModel-Y3GUP",
|
||||
"position": {
|
||||
"x": 1950.3830456413473,
|
||||
"y": 380.8161704718418
|
||||
|
|
@ -1239,18 +1240,18 @@
|
|||
}
|
||||
],
|
||||
"viewport": {
|
||||
"x": -314.93585938343927,
|
||||
"y": 168.32720664181306,
|
||||
"x": -46.935859383438924,
|
||||
"y": 110.83424076132906,
|
||||
"zoom": 0.5205627295612754
|
||||
}
|
||||
},
|
||||
"description": "This flow can be used to create a blog post following instructions from the user, using two other blogs as reference.",
|
||||
"endpoint_name": null,
|
||||
"icon": "FileText",
|
||||
"id": "92d42e25-91d4-4108-8187-92fc53fc9778",
|
||||
"id": "5e9b5662-0985-4d40-8ffe-b7f42fa86421",
|
||||
"is_component": false,
|
||||
"last_tested_version": "1.0.17",
|
||||
"last_tested_version": "1.0.19.post1",
|
||||
"name": "Blog Writer",
|
||||
"icon": "FileText",
|
||||
"tags": [
|
||||
"chatbots"
|
||||
]
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -16,7 +16,6 @@ from asgi_lifespan import LifespanManager
|
|||
from dotenv import load_dotenv
|
||||
from fastapi.testclient import TestClient
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
from langflow.components.inputs import ChatInput
|
||||
from langflow.graph import Graph
|
||||
from langflow.initial_setup.setup import STARTER_FOLDER_NAME
|
||||
from langflow.services.auth.utils import get_password_hash
|
||||
|
|
@ -531,6 +530,8 @@ async def added_webhook_test(client, json_webhook_test, logged_in_headers):
|
|||
|
||||
@pytest.fixture
|
||||
async def flow_component(client: AsyncClient, logged_in_headers):
|
||||
from langflow.components.inputs import ChatInput
|
||||
|
||||
chat_input = ChatInput()
|
||||
graph = Graph(start=chat_input, end=chat_input)
|
||||
graph_dict = graph.dump(name="Chat Input Component")
|
||||
|
|
|
|||
|
|
@ -48,9 +48,7 @@ def test_update_build_config_exceed_limit(create_data_component):
|
|||
"value": False,
|
||||
},
|
||||
}
|
||||
with pytest.raises(
|
||||
ValueError, match="Number of fields cannot exceed 15. Try using a Component to combine two Data."
|
||||
):
|
||||
with pytest.raises(ValueError, match="Number of fields cannot exceed 15."):
|
||||
create_data_component.update_build_config(build_config, 16, "number_of_fields")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -48,9 +48,7 @@ def test_update_build_config_exceed_limit(update_data_component):
|
|||
"value": False,
|
||||
},
|
||||
}
|
||||
with pytest.raises(
|
||||
ValueError, match="Number of fields cannot exceed 15. Try using a Component to combine two Data."
|
||||
):
|
||||
with pytest.raises(ValueError, match="Number of fields cannot exceed 15."):
|
||||
update_data_component.update_build_config(build_config, 16, "number_of_fields")
|
||||
|
||||
|
||||
|
|
@ -94,6 +92,9 @@ def test_validate_text_key_valid(update_data_component):
|
|||
def test_validate_text_key_invalid(update_data_component):
|
||||
data = Data(data={"key1": "value1", "key2": "value2"}, text_key="key1")
|
||||
update_data_component.text_key = "invalid_key"
|
||||
|
||||
with pytest.raises(ValueError, match="Text Key: invalid_key not found in the Data keys: key1,key2"):
|
||||
with pytest.raises(ValueError) as exc_info: # noqa: PT011
|
||||
update_data_component.validate_text_key(data)
|
||||
expected_error_message = (
|
||||
f"Text Key: '{update_data_component.text_key}' not found in the Data keys: {', '.join(data.data.keys())}"
|
||||
)
|
||||
assert str(exc_info.value) == expected_error_message
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue