ref: Add ruff rules for pydocstyle (D) (#4120)
Add ruff rules for pydocstyle (D)
This commit is contained in:
parent
3e181b91c6
commit
b1a79c0749
119 changed files with 634 additions and 1245 deletions
|
|
@ -46,9 +46,7 @@ def get_number_of_workers(workers=None):
|
||||||
|
|
||||||
|
|
||||||
def display_results(results):
|
def display_results(results):
|
||||||
"""
|
"""Display the results of the migration."""
|
||||||
Display the results of the migration.
|
|
||||||
"""
|
|
||||||
for table_results in results:
|
for table_results in results:
|
||||||
table = Table(title=f"Migration {table_results.table_name}")
|
table = Table(title=f"Migration {table_results.table_name}")
|
||||||
table.add_column("Name")
|
table.add_column("Name")
|
||||||
|
|
@ -149,10 +147,7 @@ def run(
|
||||||
show_default=False,
|
show_default=False,
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
"""
|
"""Run Langflow."""
|
||||||
Run Langflow.
|
|
||||||
"""
|
|
||||||
|
|
||||||
configure(log_level=log_level, log_file=log_file)
|
configure(log_level=log_level, log_file=log_file)
|
||||||
set_var_for_macos_issue()
|
set_var_for_macos_issue()
|
||||||
|
|
||||||
|
|
@ -225,9 +220,7 @@ def run(
|
||||||
|
|
||||||
|
|
||||||
def wait_for_server_ready(host, port):
|
def wait_for_server_ready(host, port):
|
||||||
"""
|
"""Wait for the server to become ready by polling the health endpoint."""
|
||||||
Wait for the server to become ready by polling the health endpoint.
|
|
||||||
"""
|
|
||||||
status_code = 0
|
status_code = 0
|
||||||
while status_code != httpx.codes.OK:
|
while status_code != httpx.codes.OK:
|
||||||
try:
|
try:
|
||||||
|
|
@ -249,16 +242,13 @@ def run_on_mac_or_linux(host, port, log_level, options, app):
|
||||||
|
|
||||||
|
|
||||||
def run_on_windows(host, port, log_level, options, app):
|
def run_on_windows(host, port, log_level, options, app):
|
||||||
"""
|
"""Run the Langflow server on Windows."""
|
||||||
Run the Langflow server on Windows.
|
|
||||||
"""
|
|
||||||
print_banner(host, port)
|
print_banner(host, port)
|
||||||
run_langflow(host, port, log_level, options, app)
|
run_langflow(host, port, log_level, options, app)
|
||||||
|
|
||||||
|
|
||||||
def is_port_in_use(port, host="localhost"):
|
def is_port_in_use(port, host="localhost"):
|
||||||
"""
|
"""Check if a port is in use.
|
||||||
Check if a port is in use.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
port (int): The port number to check.
|
port (int): The port number to check.
|
||||||
|
|
@ -272,8 +262,7 @@ def is_port_in_use(port, host="localhost"):
|
||||||
|
|
||||||
|
|
||||||
def get_free_port(port):
|
def get_free_port(port):
|
||||||
"""
|
"""Given a used port, find a free port.
|
||||||
Given a used port, find a free port.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
port (int): The port number to check.
|
port (int): The port number to check.
|
||||||
|
|
@ -287,9 +276,7 @@ def get_free_port(port):
|
||||||
|
|
||||||
|
|
||||||
def get_letter_from_version(version: str):
|
def get_letter_from_version(version: str):
|
||||||
"""
|
"""Get the letter from a pre-release version."""
|
||||||
Get the letter from a pre-release version.
|
|
||||||
"""
|
|
||||||
if "a" in version:
|
if "a" in version:
|
||||||
return "a"
|
return "a"
|
||||||
if "b" in version:
|
if "b" in version:
|
||||||
|
|
@ -308,9 +295,7 @@ def build_version_notice(current_version: str, package_name: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def generate_pip_command(package_names, is_pre_release):
|
def generate_pip_command(package_names, is_pre_release):
|
||||||
"""
|
"""Generate the pip install command based on the packages and whether it's a pre-release."""
|
||||||
Generate the pip install command based on the packages and whether it's a pre-release.
|
|
||||||
"""
|
|
||||||
base_command = "pip install"
|
base_command = "pip install"
|
||||||
if is_pre_release:
|
if is_pre_release:
|
||||||
return f"{base_command} {' '.join(package_names)} -U --pre"
|
return f"{base_command} {' '.join(package_names)} -U --pre"
|
||||||
|
|
@ -369,10 +354,7 @@ def print_banner(host: str, port: int):
|
||||||
|
|
||||||
|
|
||||||
def run_langflow(host, port, log_level, options, app):
|
def run_langflow(host, port, log_level, options, app):
|
||||||
"""
|
"""Run Langflow server on localhost."""
|
||||||
Run Langflow server on localhost
|
|
||||||
"""
|
|
||||||
|
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
# Run using uvicorn on MacOS and Windows
|
# Run using uvicorn on MacOS and Windows
|
||||||
# Windows doesn't support gunicorn
|
# Windows doesn't support gunicorn
|
||||||
|
|
@ -398,9 +380,7 @@ def superuser(
|
||||||
password: str = typer.Option(..., prompt=True, hide_input=True, help="Password for the superuser."),
|
password: str = typer.Option(..., prompt=True, hide_input=True, help="Password for the superuser."),
|
||||||
log_level: str = typer.Option("error", help="Logging level.", envvar="LANGFLOW_LOG_LEVEL"),
|
log_level: str = typer.Option("error", help="Logging level.", envvar="LANGFLOW_LOG_LEVEL"),
|
||||||
):
|
):
|
||||||
"""
|
"""Create a superuser."""
|
||||||
Create a superuser.
|
|
||||||
"""
|
|
||||||
configure(log_level=log_level)
|
configure(log_level=log_level)
|
||||||
initialize_services()
|
initialize_services()
|
||||||
db_service = get_db_service()
|
db_service = get_db_service()
|
||||||
|
|
@ -432,8 +412,7 @@ def superuser(
|
||||||
# because now the database is stored per installation
|
# because now the database is stored per installation
|
||||||
@app.command()
|
@app.command()
|
||||||
def copy_db():
|
def copy_db():
|
||||||
"""
|
"""Copy the database files to the current directory.
|
||||||
Copy the database files to the current directory.
|
|
||||||
|
|
||||||
This function copies the 'langflow.db' and 'langflow-pre.db' files from the cache directory to the current
|
This function copies the 'langflow.db' and 'langflow-pre.db' files from the cache directory to the current
|
||||||
directory.
|
directory.
|
||||||
|
|
@ -472,9 +451,7 @@ def migration(
|
||||||
help="Fix migrations. This is a destructive operation, and should only be used if you know what you are doing.",
|
help="Fix migrations. This is a destructive operation, and should only be used if you know what you are doing.",
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
"""
|
"""Run or test migrations."""
|
||||||
Run or test migrations.
|
|
||||||
"""
|
|
||||||
if fix and not typer.confirm(
|
if fix and not typer.confirm(
|
||||||
"This will delete all data necessary to fix migrations. Are you sure you want to continue?"
|
"This will delete all data necessary to fix migrations. Are you sure you want to continue?"
|
||||||
):
|
):
|
||||||
|
|
@ -492,8 +469,7 @@ def migration(
|
||||||
def api_key(
|
def api_key(
|
||||||
log_level: str = typer.Option("error", help="Logging level."),
|
log_level: str = typer.Option("error", help="Logging level."),
|
||||||
):
|
):
|
||||||
"""
|
"""Creates an API key for the default superuser if AUTO_LOGIN is enabled.
|
||||||
Creates an API key for the default superuser if AUTO_LOGIN is enabled.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
log_level (str, optional): Logging level. Defaults to "error".
|
log_level (str, optional): Logging level. Defaults to "error".
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,10 @@ async def event_generator(request: Request):
|
||||||
async def stream_logs(
|
async def stream_logs(
|
||||||
request: Request,
|
request: Request,
|
||||||
):
|
):
|
||||||
"""
|
"""HTTP/2 Server-Sent-Event (SSE) endpoint for streaming logs.
|
||||||
HTTP/2 Server-Sent-Event (SSE) endpoint for streaming logs
|
|
||||||
it establishes a long-lived connection to the server and receives log messages in real-time
|
It establishes a long-lived connection to the server and receives log messages in real-time.
|
||||||
the client should use the head "Accept: text/event-stream"
|
The client should use the header "Accept: text/event-stream".
|
||||||
"""
|
"""
|
||||||
global log_buffer # noqa: PLW0602
|
global log_buffer # noqa: PLW0602
|
||||||
if log_buffer.enabled() is False:
|
if log_buffer.enabled() is False:
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ def remove_api_keys(flow: dict):
|
||||||
|
|
||||||
def build_input_keys_response(langchain_object, artifacts):
|
def build_input_keys_response(langchain_object, artifacts):
|
||||||
"""Build the input keys response."""
|
"""Build the input keys response."""
|
||||||
|
|
||||||
input_keys_response = {
|
input_keys_response = {
|
||||||
"input_keys": dict.fromkeys(langchain_object.input_keys, ""),
|
"input_keys": dict.fromkeys(langchain_object.input_keys, ""),
|
||||||
"memory_keys": [],
|
"memory_keys": [],
|
||||||
|
|
@ -201,8 +200,7 @@ def format_exception_message(exc: Exception) -> str:
|
||||||
|
|
||||||
|
|
||||||
def get_top_level_vertices(graph, vertices_ids):
|
def get_top_level_vertices(graph, vertices_ids):
|
||||||
"""
|
"""Retrieves the top-level vertices from the given graph based on the provided vertex IDs.
|
||||||
Retrieves the top-level vertices from the given graph based on the provided vertex IDs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
graph (Graph): The graph object containing the vertices.
|
graph (Graph): The graph object containing the vertices.
|
||||||
|
|
|
||||||
|
|
@ -78,16 +78,17 @@ async def retrieve_vertices_order(
|
||||||
session=Depends(get_session),
|
session=Depends(get_session),
|
||||||
telemetry_service: TelemetryService = Depends(get_telemetry_service),
|
telemetry_service: TelemetryService = Depends(get_telemetry_service),
|
||||||
):
|
):
|
||||||
"""
|
"""Retrieve the vertices order for a given flow.
|
||||||
Retrieve the vertices order for a given flow.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
flow_id (str): The ID of the flow.
|
flow_id (str): The ID of the flow.
|
||||||
|
background_tasks (BackgroundTasks): The background tasks.
|
||||||
data (Optional[FlowDataRequest], optional): The flow data. Defaults to None.
|
data (Optional[FlowDataRequest], optional): The flow data. Defaults to None.
|
||||||
stop_component_id (str, optional): The ID of the stop component. Defaults to None.
|
stop_component_id (str, optional): The ID of the stop component. Defaults to None.
|
||||||
start_component_id (str, optional): The ID of the start component. Defaults to None.
|
start_component_id (str, optional): The ID of the start component. Defaults to None.
|
||||||
chat_service (ChatService, optional): The chat service dependency. Defaults to Depends(get_chat_service).
|
chat_service (ChatService, optional): The chat service dependency. Defaults to Depends(get_chat_service).
|
||||||
session (Session, optional): The session dependency. Defaults to Depends(get_session).
|
session (Session, optional): The session dependency. Defaults to Depends(get_session).
|
||||||
|
telemetry_service (TelemetryService, optional): The telemetry service.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
VerticesOrderResponse: The response containing the ordered vertex IDs and the run ID.
|
VerticesOrderResponse: The response containing the ordered vertex IDs and the run ID.
|
||||||
|
|
@ -471,8 +472,10 @@ async def build_vertex(
|
||||||
vertex_id (str): The ID of the vertex to build.
|
vertex_id (str): The ID of the vertex to build.
|
||||||
background_tasks (BackgroundTasks): The background tasks dependency.
|
background_tasks (BackgroundTasks): The background tasks dependency.
|
||||||
inputs (Optional[InputValueRequest], optional): The input values for the vertex. Defaults to None.
|
inputs (Optional[InputValueRequest], optional): The input values for the vertex. Defaults to None.
|
||||||
|
files (List[str], optional): The files to use. Defaults to None.
|
||||||
chat_service (ChatService, optional): The chat service dependency. Defaults to Depends(get_chat_service).
|
chat_service (ChatService, optional): The chat service dependency. Defaults to Depends(get_chat_service).
|
||||||
current_user (Any, optional): The current user dependency. Defaults to Depends(get_current_active_user).
|
current_user (Any, optional): The current user dependency. Defaults to Depends(get_current_active_user).
|
||||||
|
telemetry_service (TelemetryService, optional): The telemetry service.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
VertexBuildResponse: The response containing the built vertex information.
|
VertexBuildResponse: The response containing the built vertex information.
|
||||||
|
|
|
||||||
|
|
@ -156,9 +156,7 @@ async def simple_run_flow_task(
|
||||||
stream: bool = False,
|
stream: bool = False,
|
||||||
api_key_user: User | None = None,
|
api_key_user: User | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""Run a flow task as a BackgroundTask, therefore it should not throw exceptions."""
|
||||||
Run a flow task as a BackgroundTask, therefore it should not throw exceptions.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
return await simple_run_flow(
|
return await simple_run_flow(
|
||||||
flow=flow,
|
flow=flow,
|
||||||
|
|
@ -180,9 +178,10 @@ async def simplified_run_flow(
|
||||||
api_key_user: UserRead = Depends(api_key_security),
|
api_key_user: UserRead = Depends(api_key_security),
|
||||||
telemetry_service: TelemetryService = Depends(get_telemetry_service),
|
telemetry_service: TelemetryService = Depends(get_telemetry_service),
|
||||||
):
|
):
|
||||||
"""
|
"""Executes a specified flow by ID.
|
||||||
Executes a specified flow by ID with input customization, performance enhancements through caching, and optional
|
|
||||||
data streaming.
|
Executes a specified flow by ID with input customization, performance enhancements through caching,
|
||||||
|
and optional data streaming.
|
||||||
|
|
||||||
### Parameters:
|
### Parameters:
|
||||||
- `db` (Session): Database session for executing queries.
|
- `db` (Session): Database session for executing queries.
|
||||||
|
|
@ -301,15 +300,14 @@ async def webhook_run_flow(
|
||||||
background_tasks: BackgroundTasks,
|
background_tasks: BackgroundTasks,
|
||||||
telemetry_service: Annotated[TelemetryService, Depends(get_telemetry_service)],
|
telemetry_service: Annotated[TelemetryService, Depends(get_telemetry_service)],
|
||||||
):
|
):
|
||||||
"""
|
"""Run a flow using a webhook request.
|
||||||
Run a flow using a webhook request.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
db (Session): The database session.
|
flow (Flow, optional): The flow to be executed. Defaults to Depends(get_flow_by_id).
|
||||||
|
user (User): The flow user.
|
||||||
request (Request): The incoming HTTP request.
|
request (Request): The incoming HTTP request.
|
||||||
background_tasks (BackgroundTasks): The background tasks manager.
|
background_tasks (BackgroundTasks): The background tasks manager.
|
||||||
session_service (SessionService, optional): The session service. Defaults to Depends(get_session_service).
|
telemetry_service (TelemetryService): The telemetry service.
|
||||||
flow (Flow, optional): The flow to be executed. Defaults to Depends(get_flow_by_id).
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the status of the task.
|
dict: A dictionary containing the status of the task.
|
||||||
|
|
@ -382,8 +380,8 @@ async def experimental_run_flow(
|
||||||
api_key_user: UserRead = Depends(api_key_security),
|
api_key_user: UserRead = Depends(api_key_security),
|
||||||
session_service: SessionService = Depends(get_session_service),
|
session_service: SessionService = Depends(get_session_service),
|
||||||
):
|
):
|
||||||
"""
|
"""Executes a specified flow by ID with optional input values, output selection, tweaks, and streaming capability.
|
||||||
Executes a specified flow by ID with optional input values, output selection, tweaks, and streaming capability.
|
|
||||||
This endpoint supports running flows with caching to enhance performance and efficiency.
|
This endpoint supports running flows with caching to enhance performance and efficiency.
|
||||||
|
|
||||||
### Parameters:
|
### Parameters:
|
||||||
|
|
@ -511,9 +509,7 @@ async def process(
|
||||||
sync: Annotated[bool, Body(embed=True)] = True,
|
sync: Annotated[bool, Body(embed=True)] = True,
|
||||||
session_service: SessionService = Depends(get_session_service),
|
session_service: SessionService = Depends(get_session_service),
|
||||||
):
|
):
|
||||||
"""
|
"""Endpoint to process an input with a given flow_id."""
|
||||||
Endpoint to process an input with a given flow_id.
|
|
||||||
"""
|
|
||||||
# Raise a depreciation warning
|
# Raise a depreciation warning
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"The /process endpoint is deprecated and will be removed in a future version. Please use /run instead."
|
"The /process endpoint is deprecated and will be removed in a future version. Please use /run instead."
|
||||||
|
|
@ -598,8 +594,7 @@ async def custom_component_update(
|
||||||
code_request: UpdateCustomComponentRequest,
|
code_request: UpdateCustomComponentRequest,
|
||||||
user: Annotated[User, Depends(get_current_active_user)],
|
user: Annotated[User, Depends(get_current_active_user)],
|
||||||
):
|
):
|
||||||
"""
|
"""Update a custom component with the provided code request.
|
||||||
Update a custom component with the provided code request.
|
|
||||||
|
|
||||||
This endpoint generates the CustomComponentFrontendNode normally but then runs the `update_build_config` method
|
This endpoint generates the CustomComponentFrontendNode normally but then runs the `update_build_config` method
|
||||||
on the latest version of the template.
|
on the latest version of the template.
|
||||||
|
|
|
||||||
|
|
@ -137,8 +137,7 @@ def read_flows(
|
||||||
params: Params = Depends(),
|
params: Params = Depends(),
|
||||||
header_flows: bool = False,
|
header_flows: bool = False,
|
||||||
):
|
):
|
||||||
"""
|
"""Retrieve a list of flows with pagination support.
|
||||||
Retrieve a list of flows with pagination support.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
current_user (User): The current authenticated user.
|
current_user (User): The current authenticated user.
|
||||||
|
|
@ -149,10 +148,11 @@ def read_flows(
|
||||||
folder_id (UUID, optional): The folder ID. Defaults to None.
|
folder_id (UUID, optional): The folder ID. Defaults to None.
|
||||||
params (Params): Pagination parameters.
|
params (Params): Pagination parameters.
|
||||||
remove_example_flows (bool, optional): Whether to remove example flows. Defaults to False.
|
remove_example_flows (bool, optional): Whether to remove example flows. Defaults to False.
|
||||||
|
header_flows (bool, optional): Whether to return only specific headers of the flows. Defaults to False.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Union[list[FlowRead], Page[FlowRead]]: A list of flows or a paginated response containing the list of flows.
|
Union[list[FlowRead], Page[FlowRead]]: A list of flows or a paginated response containing the list of flows.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
auth_settings = settings_service.auth_settings
|
auth_settings = settings_service.auth_settings
|
||||||
|
|
||||||
|
|
@ -364,12 +364,12 @@ async def delete_multiple_flows(
|
||||||
user: Annotated[User, Depends(get_current_active_user)],
|
user: Annotated[User, Depends(get_current_active_user)],
|
||||||
db: Annotated[Session, Depends(get_session)],
|
db: Annotated[Session, Depends(get_session)],
|
||||||
):
|
):
|
||||||
"""
|
"""Delete multiple flows by their IDs.
|
||||||
Delete multiple flows by their IDs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
flow_ids (List[str]): The list of flow IDs to delete.
|
flow_ids (List[str]): The list of flow IDs to delete.
|
||||||
user (User, optional): The user making the request. Defaults to the current active user.
|
user (User, optional): The user making the request. Defaults to the current active user.
|
||||||
|
db (Session, optional): The database session.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the number of flows deleted.
|
dict: A dictionary containing the number of flows deleted.
|
||||||
|
|
@ -441,8 +441,7 @@ def read_basic_examples(
|
||||||
*,
|
*,
|
||||||
session: Session = Depends(get_session),
|
session: Session = Depends(get_session),
|
||||||
):
|
):
|
||||||
"""
|
"""Retrieve a list of basic example flows.
|
||||||
Retrieve a list of basic example flows.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
session (Session): The database session.
|
session (Session): The database session.
|
||||||
|
|
@ -450,7 +449,6 @@ def read_basic_examples(
|
||||||
Returns:
|
Returns:
|
||||||
list[FlowRead]: A list of basic example flows.
|
list[FlowRead]: A list of basic example flows.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get the starter folder
|
# Get the starter folder
|
||||||
starter_folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first()
|
starter_folder = session.exec(select(Folder).where(Folder.name == STARTER_FOLDER_NAME)).first()
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,7 @@ def add_user(
|
||||||
session: Annotated[Session, Depends(get_session)],
|
session: Annotated[Session, Depends(get_session)],
|
||||||
settings_service=Depends(get_settings_service),
|
settings_service=Depends(get_settings_service),
|
||||||
) -> User:
|
) -> User:
|
||||||
"""
|
"""Add a new user to the database."""
|
||||||
Add a new user to the database.
|
|
||||||
"""
|
|
||||||
new_user = User.model_validate(user, from_attributes=True)
|
new_user = User.model_validate(user, from_attributes=True)
|
||||||
try:
|
try:
|
||||||
new_user.password = get_password_hash(user.password)
|
new_user.password = get_password_hash(user.password)
|
||||||
|
|
@ -52,9 +50,7 @@ def add_user(
|
||||||
def read_current_user(
|
def read_current_user(
|
||||||
current_user: Annotated[User, Depends(get_current_active_user)],
|
current_user: Annotated[User, Depends(get_current_active_user)],
|
||||||
) -> User:
|
) -> User:
|
||||||
"""
|
"""Retrieve the current user's data."""
|
||||||
Retrieve the current user's data.
|
|
||||||
"""
|
|
||||||
return current_user
|
return current_user
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -65,9 +61,7 @@ def read_all_users(
|
||||||
_: Session = Depends(get_current_active_superuser),
|
_: Session = Depends(get_current_active_superuser),
|
||||||
session: Session = Depends(get_session),
|
session: Session = Depends(get_session),
|
||||||
) -> UsersResponse:
|
) -> UsersResponse:
|
||||||
"""
|
"""Retrieve a list of users from the database with pagination."""
|
||||||
Retrieve a list of users from the database with pagination.
|
|
||||||
"""
|
|
||||||
query: SelectOfScalar = select(User).offset(skip).limit(limit)
|
query: SelectOfScalar = select(User).offset(skip).limit(limit)
|
||||||
users = session.exec(query).fetchall()
|
users = session.exec(query).fetchall()
|
||||||
|
|
||||||
|
|
@ -87,10 +81,7 @@ def patch_user(
|
||||||
user: Annotated[User, Depends(get_current_active_user)],
|
user: Annotated[User, Depends(get_current_active_user)],
|
||||||
session: Annotated[Session, Depends(get_session)],
|
session: Annotated[Session, Depends(get_session)],
|
||||||
) -> User:
|
) -> User:
|
||||||
"""
|
"""Update an existing user's data."""
|
||||||
Update an existing user's data.
|
|
||||||
"""
|
|
||||||
|
|
||||||
update_password = user_update.password is not None and user_update.password != ""
|
update_password = user_update.password is not None and user_update.password != ""
|
||||||
|
|
||||||
if not user.is_superuser and user_update.is_superuser:
|
if not user.is_superuser and user_update.is_superuser:
|
||||||
|
|
@ -117,9 +108,7 @@ def reset_password(
|
||||||
user: Annotated[User, Depends(get_current_active_user)],
|
user: Annotated[User, Depends(get_current_active_user)],
|
||||||
session: Annotated[Session, Depends(get_session)],
|
session: Annotated[Session, Depends(get_session)],
|
||||||
) -> User:
|
) -> User:
|
||||||
"""
|
"""Reset a user's password."""
|
||||||
Reset a user's password.
|
|
||||||
"""
|
|
||||||
if user_id != user.id:
|
if user_id != user.id:
|
||||||
raise HTTPException(status_code=400, detail="You can't change another user's password")
|
raise HTTPException(status_code=400, detail="You can't change another user's password")
|
||||||
|
|
||||||
|
|
@ -141,9 +130,7 @@ def delete_user(
|
||||||
current_user: Annotated[User, Depends(get_current_active_superuser)],
|
current_user: Annotated[User, Depends(get_current_active_superuser)],
|
||||||
session: Annotated[Session, Depends(get_session)],
|
session: Annotated[Session, Depends(get_session)],
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""
|
"""Delete a user from the database."""
|
||||||
Delete a user from the database.
|
|
||||||
"""
|
|
||||||
if current_user.id == user_id:
|
if current_user.id == user_id:
|
||||||
raise HTTPException(status_code=400, detail="You can't delete your own user account")
|
raise HTTPException(status_code=400, detail="You can't delete your own user account")
|
||||||
if not current_user.is_superuser:
|
if not current_user.is_superuser:
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@ class AgentSpec(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
def data_to_messages(data: list[Data]) -> list[BaseMessage]:
|
def data_to_messages(data: list[Data]) -> list[BaseMessage]:
|
||||||
"""
|
"""Convert a list of data to a list of messages.
|
||||||
Convert a list of data to a list of messages.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data (List[Data]): The data to convert.
|
data (List[Data]): The data to convert.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
"""
|
"""This module contains constants used in the Langflow base module.
|
||||||
This module contains constants used in the Langflow base module.
|
|
||||||
|
|
||||||
Constants:
|
Constants:
|
||||||
- STREAM_INFO_TEXT: A string representing the information about streaming the response from the model.
|
- STREAM_INFO_TEXT: A string representing the information about streaming the response from the model.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
"""
|
r"""This file contains a fix for the implementation of the `uncurl` library, which is available at https://github.com/spulec/uncurl.git.
|
||||||
This file contains a fix for the implementation of the `uncurl` library, which is available at https://github.com/spulec/uncurl.git.
|
|
||||||
|
|
||||||
The `uncurl` library provides a way to parse and convert cURL commands into Python requests.
|
The `uncurl` library provides a way to parse and convert cURL commands into Python requests.
|
||||||
However, there are some issues with the original implementation that this file aims to fix.
|
However, there are some issues with the original implementation that this file aims to fix.
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,8 @@ class LCDocumentTransformerComponent(Component):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_data_input(self) -> Any:
|
def get_data_input(self) -> Any:
|
||||||
"""
|
"""Get the data input."""
|
||||||
Get the data input.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def build_document_transformer(self) -> BaseDocumentTransformer:
|
def build_document_transformer(self) -> BaseDocumentTransformer:
|
||||||
"""
|
"""Build the text splitter."""
|
||||||
Build the text splitter.
|
|
||||||
"""
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ from langflow.schema.message import Message
|
||||||
|
|
||||||
|
|
||||||
def build_data_from_run_outputs(run_outputs: RunOutputs) -> list[Data]:
|
def build_data_from_run_outputs(run_outputs: RunOutputs) -> list[Data]:
|
||||||
"""
|
"""Build a list of data from the given RunOutputs.
|
||||||
Build a list of data from the given RunOutputs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
run_outputs (RunOutputs): The RunOutputs object containing the output data.
|
run_outputs (RunOutputs): The RunOutputs object containing the output data.
|
||||||
|
|
@ -26,8 +25,7 @@ def build_data_from_run_outputs(run_outputs: RunOutputs) -> list[Data]:
|
||||||
|
|
||||||
|
|
||||||
def build_data_from_result_data(result_data: ResultData, get_final_results_only: bool = True) -> list[Data]:
|
def build_data_from_result_data(result_data: ResultData, get_final_results_only: bool = True) -> list[Data]:
|
||||||
"""
|
"""Build a list of data from the given ResultData.
|
||||||
Build a list of data from the given ResultData.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
result_data (ResultData): The ResultData object containing the result data.
|
result_data (ResultData): The ResultData object containing the result data.
|
||||||
|
|
@ -76,8 +74,7 @@ def build_data_from_result_data(result_data: ResultData, get_final_results_only:
|
||||||
|
|
||||||
|
|
||||||
def format_flow_output_data(data: list[Data]) -> str:
|
def format_flow_output_data(data: list[Data]) -> str:
|
||||||
"""
|
"""Format the flow output data into a string.
|
||||||
Format the flow output data into a string.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data (List[Data]): The list of data to format.
|
data (List[Data]): The list of data to format.
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,8 @@ class LCToolComponent(Component):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def run_model(self) -> Data | list[Data]:
|
def run_model(self) -> Data | list[Data]:
|
||||||
"""
|
"""Run model and return the output."""
|
||||||
Run model and return the output.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def build_tool(self) -> Tool | Sequence[Tool]:
|
def build_tool(self) -> Tool | Sequence[Tool]:
|
||||||
"""
|
"""Build the tool."""
|
||||||
Build the tool.
|
|
||||||
"""
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,4 @@ class LCChatMemoryComponent(Component):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def build_message_history(self) -> BaseChatMessageHistory:
|
def build_message_history(self) -> BaseChatMessageHistory:
|
||||||
"""
|
"""Builds the chat message history memory."""
|
||||||
Builds the chat message history memory.
|
|
||||||
"""
|
|
||||||
|
|
|
||||||
|
|
@ -64,11 +64,10 @@ class LCModelComponent(Component):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_result(self, runnable: LLM, stream: bool, input_value: str):
|
def get_result(self, runnable: LLM, stream: bool, input_value: str):
|
||||||
"""
|
"""Retrieves the result from the output of a Runnable object.
|
||||||
Retrieves the result from the output of a Runnable object.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
output (Runnable): The output object to retrieve the result from.
|
runnable (Runnable): The runnable to retrieve the result from.
|
||||||
stream (bool): Indicates whether to use streaming or invocation mode.
|
stream (bool): Indicates whether to use streaming or invocation mode.
|
||||||
input_value (str): The input value to pass to the output object.
|
input_value (str): The input value to pass to the output object.
|
||||||
|
|
||||||
|
|
@ -90,8 +89,7 @@ class LCModelComponent(Component):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def build_status_message(self, message: AIMessage):
|
def build_status_message(self, message: AIMessage):
|
||||||
"""
|
"""Builds a status message from an AIMessage object.
|
||||||
Builds a status message from an AIMessage object.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message (AIMessage): The AIMessage object to build the status message from.
|
message (AIMessage): The AIMessage object to build the status message from.
|
||||||
|
|
@ -204,6 +202,4 @@ class LCModelComponent(Component):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def build_model(self) -> LanguageModel: # type: ignore[type-var]
|
def build_model(self) -> LanguageModel: # type: ignore[type-var]
|
||||||
"""
|
"""Implement this method to build the model."""
|
||||||
Implement this method to build the model.
|
|
||||||
"""
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
def data_to_string(record: Data) -> str:
|
def data_to_string(record: Data) -> str:
|
||||||
"""
|
"""Convert a record to a string.
|
||||||
Convert a record to a string.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
record (Data): The record to convert.
|
record (Data): The record to convert.
|
||||||
|
|
@ -19,8 +18,7 @@ def data_to_string(record: Data) -> str:
|
||||||
|
|
||||||
|
|
||||||
def dict_values_to_string(d: dict) -> dict:
|
def dict_values_to_string(d: dict) -> dict:
|
||||||
"""
|
"""Converts the values of a dictionary to strings.
|
||||||
Converts the values of a dictionary to strings.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
d (dict): The dictionary whose values need to be converted.
|
d (dict): The dictionary whose values need to be converted.
|
||||||
|
|
@ -52,8 +50,7 @@ def dict_values_to_string(d: dict) -> dict:
|
||||||
|
|
||||||
|
|
||||||
def document_to_string(document: Document) -> str:
|
def document_to_string(document: Document) -> str:
|
||||||
"""
|
"""Convert a document to a string.
|
||||||
Convert a document to a string.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
document (Document): The document to convert.
|
document (Document): The document to convert.
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,4 @@ class LCTextSplitterComponent(LCDocumentTransformerComponent):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def build_text_splitter(self) -> TextSplitter:
|
def build_text_splitter(self) -> TextSplitter:
|
||||||
"""
|
"""Build the text splitter."""
|
||||||
Build the text splitter.
|
|
||||||
"""
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@ from langflow.field_typing import Tool
|
||||||
|
|
||||||
|
|
||||||
def build_status_from_tool(tool: Tool):
|
def build_status_from_tool(tool: Tool):
|
||||||
"""
|
"""Builds a status string representation of a tool.
|
||||||
Builds a status string representation of a tool.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tool (Tool): The tool object to build the status for.
|
tool (Tool): The tool object to build the status for.
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,6 @@ class FlowTool(BaseTool):
|
||||||
|
|
||||||
def validate_inputs(self, args_names: list[dict[str, str]], args: Any, kwargs: Any):
|
def validate_inputs(self, args_names: list[dict[str, str]], args: Any, kwargs: Any):
|
||||||
"""Validate the inputs."""
|
"""Validate the inputs."""
|
||||||
|
|
||||||
if len(args) > 0 and len(args) != len(args_names):
|
if len(args) > 0 and len(args) != len(args_names):
|
||||||
msg = "Number of positional arguments does not match the number of inputs. Pass keyword arguments instead."
|
msg = "Number of positional arguments does not match the number of inputs. Pass keyword arguments instead."
|
||||||
raise ToolException(msg)
|
raise ToolException(msg)
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
def check_cached_vector_store(f):
|
def check_cached_vector_store(f):
|
||||||
"""
|
"""Decorator to check for cached vector stores, and returns them if they exist.
|
||||||
Decorator to check for cached vector stores, and returns them if they exist.
|
|
||||||
|
|
||||||
Note: caching only occurs during the execution of a component - they do not persist
|
Note: caching only occurs during the execution of a component - they do not persist
|
||||||
across separate invocations of the component. This method exists so that components with
|
across separate invocations of the component. This method exists so that components with
|
||||||
|
|
@ -42,9 +41,7 @@ class LCVectorStoreComponent(Component):
|
||||||
_cached_vector_store: VectorStore | None = None
|
_cached_vector_store: VectorStore | None = None
|
||||||
|
|
||||||
def __init_subclass__(cls, **kwargs):
|
def __init_subclass__(cls, **kwargs):
|
||||||
"""
|
"""Enforces the check cached decorator on all subclasses."""
|
||||||
Enforces the check cached decorator on all subclasses
|
|
||||||
"""
|
|
||||||
super().__init_subclass__(**kwargs)
|
super().__init_subclass__(**kwargs)
|
||||||
if hasattr(cls, "build_vector_store"):
|
if hasattr(cls, "build_vector_store"):
|
||||||
method = cls.build_vector_store
|
method = cls.build_vector_store
|
||||||
|
|
@ -98,13 +95,14 @@ class LCVectorStoreComponent(Component):
|
||||||
k=10,
|
k=10,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> list[Data]:
|
) -> list[Data]:
|
||||||
"""
|
"""Search for data in the vector store based on the input value and search type.
|
||||||
Search for data in the vector store based on the input value and search type.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
input_value (Text): The input value to search for.
|
input_value (Text): The input value to search for.
|
||||||
search_type (str): The type of search to perform.
|
search_type (str): The type of search to perform.
|
||||||
vector_store (VectorStore): The vector store to search in.
|
vector_store (VectorStore): The vector store to search in.
|
||||||
|
k (int): The number of results to return.
|
||||||
|
**kwargs: Additional keyword arguments to pass to the vector store search method.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Data]: A list of data matching the search criteria.
|
List[Data]: A list of data matching the search criteria.
|
||||||
|
|
@ -112,7 +110,6 @@ class LCVectorStoreComponent(Component):
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If invalid inputs are provided.
|
ValueError: If invalid inputs are provided.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
docs: list[Document] = []
|
docs: list[Document] = []
|
||||||
if input_value and isinstance(input_value, str) and hasattr(vector_store, "search"):
|
if input_value and isinstance(input_value, str) and hasattr(vector_store, "search"):
|
||||||
docs = vector_store.search(query=input_value, search_type=search_type.lower(), k=k, **kwargs)
|
docs = vector_store.search(query=input_value, search_type=search_type.lower(), k=k, **kwargs)
|
||||||
|
|
@ -127,9 +124,7 @@ class LCVectorStoreComponent(Component):
|
||||||
return cast(VectorStore, self.build_vector_store())
|
return cast(VectorStore, self.build_vector_store())
|
||||||
|
|
||||||
def build_base_retriever(self) -> Retriever: # type: ignore[type-var]
|
def build_base_retriever(self) -> Retriever: # type: ignore[type-var]
|
||||||
"""
|
"""Builds the BaseRetriever object."""
|
||||||
Builds the BaseRetriever object.
|
|
||||||
"""
|
|
||||||
if self._cached_vector_store is not None:
|
if self._cached_vector_store is not None:
|
||||||
vector_store = self._cached_vector_store
|
vector_store = self._cached_vector_store
|
||||||
else:
|
else:
|
||||||
|
|
@ -145,9 +140,7 @@ class LCVectorStoreComponent(Component):
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
def search_documents(self) -> list[Data]:
|
def search_documents(self) -> list[Data]:
|
||||||
"""
|
"""Search for documents in the vector store."""
|
||||||
Search for documents in the vector store.
|
|
||||||
"""
|
|
||||||
search_query: str = self.search_query
|
search_query: str = self.search_query
|
||||||
if not search_query:
|
if not search_query:
|
||||||
self.status = ""
|
self.status = ""
|
||||||
|
|
@ -170,16 +163,12 @@ class LCVectorStoreComponent(Component):
|
||||||
return search_results
|
return search_results
|
||||||
|
|
||||||
def get_retriever_kwargs(self):
|
def get_retriever_kwargs(self):
|
||||||
"""
|
"""Get the retriever kwargs. Implementations can override this method to provide custom retriever kwargs."""
|
||||||
Get the retriever kwargs. Implementations can override this method to provide custom retriever kwargs.
|
|
||||||
"""
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@check_cached_vector_store
|
@check_cached_vector_store
|
||||||
def build_vector_store(self) -> VectorStore:
|
def build_vector_store(self) -> VectorStore:
|
||||||
"""
|
"""Builds the Vector Store object."""
|
||||||
Builds the Vector Store object.
|
|
||||||
"""
|
|
||||||
msg = "build_vector_store method must be implemented."
|
msg = "build_vector_store method must be implemented."
|
||||||
raise NotImplementedError(msg)
|
raise NotImplementedError(msg)
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
def chroma_collection_to_data(collection_dict: dict):
|
def chroma_collection_to_data(collection_dict: dict):
|
||||||
"""
|
"""Converts a collection of chroma vectors into a list of data.
|
||||||
Converts a collection of chroma vectors into a list of data.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
collection_dict (dict): A dictionary containing the collection of chroma vectors.
|
collection_dict (dict): A dictionary containing the collection of chroma vectors.
|
||||||
|
|
|
||||||
|
|
@ -93,9 +93,7 @@ class GoogleDriveSearchComponent(Component):
|
||||||
self.generate_query_string()
|
self.generate_query_string()
|
||||||
|
|
||||||
def generate_file_url(self, file_id: str, mime_type: str) -> str:
|
def generate_file_url(self, file_id: str, mime_type: str) -> str:
|
||||||
"""
|
"""Generates the appropriate Google Drive URL for a file based on its MIME type."""
|
||||||
Generates the appropriate Google Drive URL for a file based on its MIME type.
|
|
||||||
"""
|
|
||||||
return {
|
return {
|
||||||
"application/vnd.google-apps.document": f"https://docs.google.com/document/d/{file_id}/edit",
|
"application/vnd.google-apps.document": f"https://docs.google.com/document/d/{file_id}/edit",
|
||||||
"application/vnd.google-apps.spreadsheet": f"https://docs.google.com/spreadsheets/d/{file_id}/edit",
|
"application/vnd.google-apps.spreadsheet": f"https://docs.google.com/spreadsheets/d/{file_id}/edit",
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ class URLComponent(Component):
|
||||||
]
|
]
|
||||||
|
|
||||||
def ensure_url(self, string: str) -> str:
|
def ensure_url(self, string: str) -> str:
|
||||||
"""
|
"""Ensures the given string is a URL by adding 'http://' if it doesn't start with 'http://' or 'https://'.
|
||||||
Ensures the given string is a URL by adding 'http://' if it doesn't start with 'http://' or 'https://'.
|
|
||||||
Raises an error if the string is not a valid URL.
|
Raises an error if the string is not a valid URL.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@ class ExtractKeyFromDataComponent(CustomComponent):
|
||||||
}
|
}
|
||||||
|
|
||||||
def build(self, data: Data, keys: list[str], silent_error: bool = True) -> Data:
|
def build(self, data: Data, keys: list[str], silent_error: bool = True) -> Data:
|
||||||
"""
|
"""Extracts the keys from a data.
|
||||||
Extracts the keys from a data.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data (Data): The data from which to extract the keys.
|
data (Data): The data from which to extract the keys.
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
class MergeDataComponent(Component):
|
class MergeDataComponent(Component):
|
||||||
"""
|
"""MergeDataComponent is responsible for combining multiple Data objects into a unified list of Data objects.
|
||||||
MergeDataComponent is responsible for combining multiple Data objects into a unified list of Data objects.
|
|
||||||
It ensures that all keys across the input Data objects are present in each merged Data object.
|
It ensures that all keys across the input Data objects are present in each merged Data object.
|
||||||
Missing keys are filled with empty strings to maintain consistency.
|
Missing keys are filled with empty strings to maintain consistency.
|
||||||
"""
|
"""
|
||||||
|
|
@ -36,8 +36,8 @@ class MergeDataComponent(Component):
|
||||||
]
|
]
|
||||||
|
|
||||||
def merge_data(self) -> list[Data]:
|
def merge_data(self) -> list[Data]:
|
||||||
"""
|
"""Merges multiple Data objects into a single list of Data objects.
|
||||||
Merges multiple Data objects into a single list of Data objects.
|
|
||||||
Ensures that all keys from the input Data objects are present in each merged Data object.
|
Ensures that all keys from the input Data objects are present in each merged Data object.
|
||||||
Missing keys are filled with empty strings.
|
Missing keys are filled with empty strings.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ class GitLoaderComponent(Component):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_binary(file_path: str) -> bool:
|
def is_binary(file_path: str) -> bool:
|
||||||
"""
|
"""Check if a file is binary by looking for null bytes.
|
||||||
Check if a file is binary by looking for null bytes.
|
|
||||||
This is necessary because when searches are performed using
|
This is necessary because when searches are performed using
|
||||||
the content_filter, binary files need to be ignored.
|
the content_filter, binary files need to be ignored.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,9 @@ class GoogleGenerativeAIEmbeddingsComponent(Component):
|
||||||
titles: list[str] | None = None,
|
titles: list[str] | None = None,
|
||||||
output_dimensionality: int | None = 1536,
|
output_dimensionality: int | None = 1536,
|
||||||
) -> list[list[float]]:
|
) -> list[list[float]]:
|
||||||
"""Embed a list of strings. Google Generative AI currently
|
"""Embed a list of strings.
|
||||||
sets a max batch size of 100 strings.
|
|
||||||
|
Google Generative AI currently sets a max batch size of 100 strings.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
texts: List[str] The list of strings to embed.
|
texts: List[str] The list of strings to embed.
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
class MergeDataComponent(Component):
|
class MergeDataComponent(Component):
|
||||||
"""
|
"""MergeDataComponent is responsible for combining multiple Data objects into a unified list of Data objects.
|
||||||
MergeDataComponent is responsible for combining multiple Data objects into a unified list of Data objects.
|
|
||||||
It ensures that all keys across the input Data objects are present in each merged Data object.
|
It ensures that all keys across the input Data objects are present in each merged Data object.
|
||||||
Missing keys are filled with empty strings to maintain consistency.
|
Missing keys are filled with empty strings to maintain consistency.
|
||||||
"""
|
"""
|
||||||
|
|
@ -36,8 +36,8 @@ class MergeDataComponent(Component):
|
||||||
]
|
]
|
||||||
|
|
||||||
def merge_data(self) -> list[Data]:
|
def merge_data(self) -> list[Data]:
|
||||||
"""
|
"""Merges multiple Data objects into a single list of Data objects.
|
||||||
Merges multiple Data objects into a single list of Data objects.
|
|
||||||
Ensures that all keys from the input Data objects are present in each merged Data object.
|
Ensures that all keys from the input Data objects are present in each merged Data object.
|
||||||
Missing keys are filled with empty strings.
|
Missing keys are filled with empty strings.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,4 +139,4 @@ class SpiderTool(Component):
|
||||||
|
|
||||||
|
|
||||||
class SpiderToolError(Exception):
|
class SpiderToolError(Exception):
|
||||||
"""SpiderTool error"""
|
"""SpiderTool error."""
|
||||||
|
|
|
||||||
|
|
@ -93,11 +93,10 @@ class AIMLModelComponent(LCModelComponent):
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_exception_message(self, e: Exception):
|
def _get_exception_message(self, e: Exception):
|
||||||
"""
|
"""Get a message from an OpenAI exception.
|
||||||
Get a message from an OpenAI exception.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
exception (Exception): The exception to get the message from.
|
e (Exception): The exception to get the message from.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The message from the exception.
|
str: The message from the exception.
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,7 @@ class AnthropicModelComponent(LCModelComponent):
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def _get_exception_message(self, exception: Exception) -> str | None:
|
def _get_exception_message(self, exception: Exception) -> str | None:
|
||||||
"""
|
"""Get a message from an Anthropic exception.
|
||||||
Get a message from an Anthropic exception.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
exception (Exception): The exception to get the message from.
|
exception (Exception): The exception to get the message from.
|
||||||
|
|
|
||||||
|
|
@ -122,16 +122,14 @@ class OpenAIModelComponent(LCModelComponent):
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def _get_exception_message(self, e: Exception):
|
def _get_exception_message(self, e: Exception):
|
||||||
"""
|
"""Get a message from an OpenAI exception.
|
||||||
Get a message from an OpenAI exception.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
exception (Exception): The exception to get the message from.
|
e (Exception): The exception to get the message from.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The message from the exception.
|
str: The message from the exception.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from openai import BadRequestError
|
from openai import BadRequestError
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,7 @@ class PromptComponent(Component):
|
||||||
return frontend_node
|
return frontend_node
|
||||||
|
|
||||||
def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):
|
def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):
|
||||||
"""
|
"""This function is called after the code validation is done."""
|
||||||
This function is called after the code validation is done.
|
|
||||||
"""
|
|
||||||
frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)
|
frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)
|
||||||
template = frontend_node["template"]["template"]["value"]
|
template = frontend_node["template"]["template"]["value"]
|
||||||
# Kept it duplicated for backwards compatibility
|
# Kept it duplicated for backwards compatibility
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ class CreateDataComponent(Component):
|
||||||
return return_data
|
return return_data
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
"""Function to get the Data from the attributes"""
|
"""Function to get the Data from the attributes."""
|
||||||
data = {}
|
data = {}
|
||||||
for value_dict in self._attributes.values():
|
for value_dict in self._attributes.values():
|
||||||
if isinstance(value_dict, dict):
|
if isinstance(value_dict, dict):
|
||||||
|
|
@ -100,7 +100,7 @@ class CreateDataComponent(Component):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def validate_text_key(self):
|
def validate_text_key(self):
|
||||||
"""This function validates that the Text Key is one of the keys in the Data"""
|
"""This function validates that the Text Key is one of the keys in the Data."""
|
||||||
data_keys = self.get_data().keys()
|
data_keys = self.get_data().keys()
|
||||||
if self.text_key not in data_keys and self.text_key != "":
|
if self.text_key not in data_keys and self.text_key != "":
|
||||||
formatted_data_keys = ", ".join(data_keys)
|
formatted_data_keys = ", ".join(data_keys)
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,7 @@ class FlowToolComponent(LCToolComponent):
|
||||||
return [flow_data.data["name"] for flow_data in flow_datas]
|
return [flow_data.data["name"] for flow_data in flow_datas]
|
||||||
|
|
||||||
def get_flow(self, flow_name: str) -> Data | None:
|
def get_flow(self, flow_name: str) -> Data | None:
|
||||||
"""
|
"""Retrieves a flow by its name.
|
||||||
Retrieves a flow by its name.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
flow_name (str): The name of the flow to retrieve.
|
flow_name (str): The name of the flow to retrieve.
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,7 @@ class RunnableExecComponent(Component):
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_output(self, result, input_key, output_key):
|
def get_output(self, result, input_key, output_key):
|
||||||
"""
|
"""Retrieves the output value from the given result dictionary based on the specified input and output keys.
|
||||||
Retrieves the output value from the given result dictionary based on the specified input and output keys.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
result (dict): The result dictionary containing the output value.
|
result (dict): The result dictionary containing the output value.
|
||||||
|
|
@ -92,8 +91,7 @@ class RunnableExecComponent(Component):
|
||||||
return result_value, status
|
return result_value, status
|
||||||
|
|
||||||
def get_input_dict(self, runnable, input_key, input_value):
|
def get_input_dict(self, runnable, input_key, input_value):
|
||||||
"""
|
"""Returns a dictionary containing the input key-value pair for the given runnable.
|
||||||
Returns a dictionary containing the input key-value pair for the given runnable.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
runnable: The runnable object.
|
runnable: The runnable object.
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ class UpdateDataComponent(Component):
|
||||||
return self.old_data
|
return self.old_data
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
"""Function to get the Data from the attributes"""
|
"""Function to get the Data from the attributes."""
|
||||||
data = {}
|
data = {}
|
||||||
for value_dict in self._attributes.values():
|
for value_dict in self._attributes.values():
|
||||||
if isinstance(value_dict, dict):
|
if isinstance(value_dict, dict):
|
||||||
|
|
@ -107,7 +107,7 @@ class UpdateDataComponent(Component):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def validate_text_key(self, data: Data):
|
def validate_text_key(self, data: Data):
|
||||||
"""This function validates that the Text Key is one of the keys in the Data"""
|
"""This function validates that the Text Key is one of the keys in the Data."""
|
||||||
data_keys = data.data.keys()
|
data_keys = data.data.keys()
|
||||||
if self.text_key not in data_keys and self.text_key != "":
|
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)}"
|
msg = f"Text Key: {self.text_key} not found in the Data keys: {','.join(data_keys)}"
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,7 @@ from langflow.field_typing.constants import LanguageModel
|
||||||
|
|
||||||
|
|
||||||
class VectaraSelfQueryRetriverComponent(CustomComponent):
|
class VectaraSelfQueryRetriverComponent(CustomComponent):
|
||||||
"""
|
"""A custom component for implementing Vectara Self Query Retriever using a vector store."""
|
||||||
A custom component for implementing Vectara Self Query Retriever using a vector store.
|
|
||||||
"""
|
|
||||||
|
|
||||||
display_name: str = "Vectara Self Query Retriever for Vectara Vector Store"
|
display_name: str = "Vectara Self Query Retriever for Vectara Vector Store"
|
||||||
description: str = "Implementation of Vectara Self Query Retriever"
|
description: str = "Implementation of Vectara Self Query Retriever"
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,7 @@ class ComposioAPIComponent(LCToolComponent):
|
||||||
]
|
]
|
||||||
|
|
||||||
def _check_for_authorization(self, app: str) -> str:
|
def _check_for_authorization(self, app: str) -> str:
|
||||||
"""
|
"""Checks if the app is authorized.
|
||||||
Checks if the app is authorized.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
app (str): The app name to check authorization for.
|
app (str): The app name to check authorization for.
|
||||||
|
|
@ -71,8 +70,7 @@ class ComposioAPIComponent(LCToolComponent):
|
||||||
return f"{app} CONNECTED"
|
return f"{app} CONNECTED"
|
||||||
|
|
||||||
def _handle_authorization_failure(self, toolset: ComposioToolSet, entity: Any, app: str) -> str:
|
def _handle_authorization_failure(self, toolset: ComposioToolSet, entity: Any, app: str) -> str:
|
||||||
"""
|
"""Handles the authorization failure by attempting to process API key auth or initiate default connection.
|
||||||
Handles the authorization failure by attempting to process API key auth or initiate default connection.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
toolset (ComposioToolSet): The toolset instance.
|
toolset (ComposioToolSet): The toolset instance.
|
||||||
|
|
@ -92,8 +90,7 @@ class ComposioAPIComponent(LCToolComponent):
|
||||||
return "Error"
|
return "Error"
|
||||||
|
|
||||||
def _process_api_key_auth(self, entity: Any, app: str) -> str:
|
def _process_api_key_auth(self, entity: Any, app: str) -> str:
|
||||||
"""
|
"""Processes the API key authentication.
|
||||||
Processes the API key authentication.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
entity (Any): The entity instance.
|
entity (Any): The entity instance.
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,7 @@ class GleanSearchAPIComponent(LCToolComponent):
|
||||||
]
|
]
|
||||||
|
|
||||||
class GleanAPIWrapper(BaseModel):
|
class GleanAPIWrapper(BaseModel):
|
||||||
"""
|
"""Wrapper around Glean API."""
|
||||||
Wrapper around Glean API.
|
|
||||||
"""
|
|
||||||
|
|
||||||
glean_api_url: str
|
glean_api_url: str
|
||||||
glean_access_token: str
|
glean_access_token: str
|
||||||
|
|
|
||||||
|
|
@ -209,9 +209,7 @@ class PythonCodeStructuredTool(LCToolComponent):
|
||||||
)
|
)
|
||||||
|
|
||||||
def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):
|
def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):
|
||||||
"""
|
"""This function is called after the code validation is done."""
|
||||||
This function is called after the code validation is done.
|
|
||||||
"""
|
|
||||||
frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)
|
frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)
|
||||||
frontend_node["template"] = self.update_build_config(
|
frontend_node["template"] = self.update_build_config(
|
||||||
frontend_node["template"], frontend_node["template"]["tool_code"]["value"], "tool_code"
|
frontend_node["template"], frontend_node["template"]["tool_code"]["value"], "tool_code"
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,7 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
class ChromaVectorStoreComponent(LCVectorStoreComponent):
|
class ChromaVectorStoreComponent(LCVectorStoreComponent):
|
||||||
"""
|
"""Chroma Vector Store with search capabilities."""
|
||||||
Chroma Vector Store with search capabilities
|
|
||||||
"""
|
|
||||||
|
|
||||||
display_name: str = "Chroma DB"
|
display_name: str = "Chroma DB"
|
||||||
description: str = "Chroma Vector Store with search capabilities"
|
description: str = "Chroma Vector Store with search capabilities"
|
||||||
|
|
@ -96,9 +94,7 @@ class ChromaVectorStoreComponent(LCVectorStoreComponent):
|
||||||
|
|
||||||
@check_cached_vector_store
|
@check_cached_vector_store
|
||||||
def build_vector_store(self) -> Chroma:
|
def build_vector_store(self) -> Chroma:
|
||||||
"""
|
"""Builds the Chroma object."""
|
||||||
Builds the Chroma object.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
from chromadb import Client
|
from chromadb import Client
|
||||||
from langchain_chroma import Chroma
|
from langchain_chroma import Chroma
|
||||||
|
|
@ -133,9 +129,7 @@ class ChromaVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return chroma
|
return chroma
|
||||||
|
|
||||||
def _add_documents_to_vector_store(self, vector_store: "Chroma") -> None:
|
def _add_documents_to_vector_store(self, vector_store: "Chroma") -> None:
|
||||||
"""
|
"""Adds documents to the Vector Store."""
|
||||||
Adds documents to the Vector Store.
|
|
||||||
"""
|
|
||||||
if not self.ingest_data:
|
if not self.ingest_data:
|
||||||
self.status = ""
|
self.status = ""
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,7 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
"""
|
"""Elasticsearch Vector Store with with advanced, customizable search capabilities."""
|
||||||
Elasticsearch Vector Store with with advanced, customizable search capabilities.
|
|
||||||
"""
|
|
||||||
|
|
||||||
display_name: str = "Elasticsearch"
|
display_name: str = "Elasticsearch"
|
||||||
description: str = "Elasticsearch Vector Store with with advanced, customizable search capabilities."
|
description: str = "Elasticsearch Vector Store with with advanced, customizable search capabilities."
|
||||||
|
|
@ -116,9 +114,7 @@ class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
|
|
||||||
@check_cached_vector_store
|
@check_cached_vector_store
|
||||||
def build_vector_store(self) -> ElasticsearchStore:
|
def build_vector_store(self) -> ElasticsearchStore:
|
||||||
"""
|
"""Builds the Elasticsearch Vector Store object."""
|
||||||
Builds the Elasticsearch Vector Store object.
|
|
||||||
"""
|
|
||||||
if self.cloud_id and self.elasticsearch_url:
|
if self.cloud_id and self.elasticsearch_url:
|
||||||
msg = (
|
msg = (
|
||||||
"Both 'cloud_id' and 'elasticsearch_url' provided. "
|
"Both 'cloud_id' and 'elasticsearch_url' provided. "
|
||||||
|
|
@ -152,9 +148,7 @@ class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return elasticsearch
|
return elasticsearch
|
||||||
|
|
||||||
def _prepare_documents(self) -> list[Document]:
|
def _prepare_documents(self) -> list[Document]:
|
||||||
"""
|
"""Prepares documents from the input data to add to the vector store."""
|
||||||
Prepares documents from the input data to add to the vector store.
|
|
||||||
"""
|
|
||||||
documents = []
|
documents = []
|
||||||
for data in self.ingest_data:
|
for data in self.ingest_data:
|
||||||
if isinstance(data, Data):
|
if isinstance(data, Data):
|
||||||
|
|
@ -166,9 +160,7 @@ class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return documents
|
return documents
|
||||||
|
|
||||||
def _add_documents_to_vector_store(self, vector_store: "ElasticsearchStore") -> None:
|
def _add_documents_to_vector_store(self, vector_store: "ElasticsearchStore") -> None:
|
||||||
"""
|
"""Adds documents to the Vector Store."""
|
||||||
Adds documents to the Vector Store.
|
|
||||||
"""
|
|
||||||
documents = self._prepare_documents()
|
documents = self._prepare_documents()
|
||||||
if documents and self.embedding:
|
if documents and self.embedding:
|
||||||
logger.debug(f"Adding {len(documents)} documents to the Vector Store.")
|
logger.debug(f"Adding {len(documents)} documents to the Vector Store.")
|
||||||
|
|
@ -177,10 +169,7 @@ class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
logger.debug("No documents to add to the Vector Store.")
|
logger.debug("No documents to add to the Vector Store.")
|
||||||
|
|
||||||
def search(self, query: str | None = None) -> list[dict[str, Any]]:
|
def search(self, query: str | None = None) -> list[dict[str, Any]]:
|
||||||
"""
|
"""Search for similar documents in the vector store or retrieve all documents if no query is provided."""
|
||||||
Search for similar documents in the vector store or retrieve all documents
|
|
||||||
if no query is provided.
|
|
||||||
"""
|
|
||||||
vector_store = self.build_vector_store()
|
vector_store = self.build_vector_store()
|
||||||
search_kwargs = {
|
search_kwargs = {
|
||||||
"k": self.number_of_results,
|
"k": self.number_of_results,
|
||||||
|
|
@ -212,9 +201,7 @@ class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return [{"page_content": doc.page_content, "metadata": doc.metadata, "score": score} for doc, score in results]
|
return [{"page_content": doc.page_content, "metadata": doc.metadata, "score": score} for doc, score in results]
|
||||||
|
|
||||||
def get_all_documents(self, vector_store: ElasticsearchStore, **kwargs) -> list[tuple[Document, float]]:
|
def get_all_documents(self, vector_store: ElasticsearchStore, **kwargs) -> list[tuple[Document, float]]:
|
||||||
"""
|
"""Retrieve all documents from the vector store."""
|
||||||
Retrieve all documents from the vector store.
|
|
||||||
"""
|
|
||||||
client = vector_store.client
|
client = vector_store.client
|
||||||
index_name = self.index_name
|
index_name = self.index_name
|
||||||
|
|
||||||
|
|
@ -237,8 +224,8 @@ class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def search_documents(self) -> list[Data]:
|
def search_documents(self) -> list[Data]:
|
||||||
"""
|
"""Search for documents in the vector store based on the search input.
|
||||||
Search for documents in the vector store based on the search input.
|
|
||||||
If no search input is provided, retrieve all documents.
|
If no search input is provided, retrieve all documents.
|
||||||
"""
|
"""
|
||||||
results = self.search(self.search_input)
|
results = self.search(self.search_input)
|
||||||
|
|
@ -253,9 +240,7 @@ class ElasticsearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return retrieved_data
|
return retrieved_data
|
||||||
|
|
||||||
def get_retriever_kwargs(self):
|
def get_retriever_kwargs(self):
|
||||||
"""
|
"""Get the keyword arguments for the retriever."""
|
||||||
Get the keyword arguments for the retriever.
|
|
||||||
"""
|
|
||||||
return {
|
return {
|
||||||
"search_type": self.search_type.lower(),
|
"search_type": self.search_type.lower(),
|
||||||
"search_kwargs": {
|
"search_kwargs": {
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
class FaissVectorStoreComponent(LCVectorStoreComponent):
|
class FaissVectorStoreComponent(LCVectorStoreComponent):
|
||||||
"""
|
"""FAISS Vector Store with search capabilities."""
|
||||||
FAISS Vector Store with search capabilities
|
|
||||||
"""
|
|
||||||
|
|
||||||
display_name: str = "FAISS"
|
display_name: str = "FAISS"
|
||||||
description: str = "FAISS Vector Store with search capabilities"
|
description: str = "FAISS Vector Store with search capabilities"
|
||||||
|
|
@ -58,9 +56,7 @@ class FaissVectorStoreComponent(LCVectorStoreComponent):
|
||||||
|
|
||||||
@check_cached_vector_store
|
@check_cached_vector_store
|
||||||
def build_vector_store(self) -> FAISS:
|
def build_vector_store(self) -> FAISS:
|
||||||
"""
|
"""Builds the FAISS object."""
|
||||||
Builds the FAISS object.
|
|
||||||
"""
|
|
||||||
if not self.persist_directory:
|
if not self.persist_directory:
|
||||||
msg = "Folder path is required to save the FAISS index."
|
msg = "Folder path is required to save the FAISS index."
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
@ -80,9 +76,7 @@ class FaissVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return faiss
|
return faiss
|
||||||
|
|
||||||
def search_documents(self) -> list[Data]:
|
def search_documents(self) -> list[Data]:
|
||||||
"""
|
"""Search for documents in the FAISS vector store."""
|
||||||
Search for documents in the FAISS vector store.
|
|
||||||
"""
|
|
||||||
if not self.persist_directory:
|
if not self.persist_directory:
|
||||||
msg = "Folder path is required to load the FAISS index."
|
msg = "Folder path is required to load the FAISS index."
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
class MilvusVectorStoreComponent(LCVectorStoreComponent):
|
class MilvusVectorStoreComponent(LCVectorStoreComponent):
|
||||||
"""Milvus vector store with search capabilities"""
|
"""Milvus vector store with search capabilities."""
|
||||||
|
|
||||||
display_name: str = "Milvus"
|
display_name: str = "Milvus"
|
||||||
description: str = "Milvus vector store with search capabilities"
|
description: str = "Milvus vector store with search capabilities"
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,7 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
class OpenSearchVectorStoreComponent(LCVectorStoreComponent):
|
class OpenSearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
"""
|
"""OpenSearch Vector Store with advanced, customizable search capabilities."""
|
||||||
OpenSearch Vector Store with advanced, customizable search capabilities.
|
|
||||||
"""
|
|
||||||
|
|
||||||
display_name: str = "OpenSearch"
|
display_name: str = "OpenSearch"
|
||||||
description: str = "OpenSearch Vector Store with advanced, customizable search capabilities."
|
description: str = "OpenSearch Vector Store with advanced, customizable search capabilities."
|
||||||
|
|
@ -117,9 +115,7 @@ class OpenSearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
|
|
||||||
@check_cached_vector_store
|
@check_cached_vector_store
|
||||||
def build_vector_store(self) -> OpenSearchVectorSearch:
|
def build_vector_store(self) -> OpenSearchVectorSearch:
|
||||||
"""
|
"""Builds the OpenSearch Vector Store object."""
|
||||||
Builds the OpenSearch Vector Store object.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
from langchain_community.vectorstores import OpenSearchVectorSearch
|
from langchain_community.vectorstores import OpenSearchVectorSearch
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
|
|
@ -149,9 +145,7 @@ class OpenSearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return opensearch
|
return opensearch
|
||||||
|
|
||||||
def _add_documents_to_vector_store(self, vector_store: "OpenSearchVectorSearch") -> None:
|
def _add_documents_to_vector_store(self, vector_store: "OpenSearchVectorSearch") -> None:
|
||||||
"""
|
"""Adds documents to the Vector Store."""
|
||||||
Adds documents to the Vector Store.
|
|
||||||
"""
|
|
||||||
documents = []
|
documents = []
|
||||||
for _input in self.ingest_data or []:
|
for _input in self.ingest_data or []:
|
||||||
if isinstance(_input, Data):
|
if isinstance(_input, Data):
|
||||||
|
|
@ -173,9 +167,7 @@ class OpenSearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
logger.debug("No documents to add to the Vector Store.")
|
logger.debug("No documents to add to the Vector Store.")
|
||||||
|
|
||||||
def search(self, query: str | None = None) -> list[dict[str, Any]]:
|
def search(self, query: str | None = None) -> list[dict[str, Any]]:
|
||||||
"""
|
"""Search for similar documents in the vector store or retrieve all documents if no query is provided."""
|
||||||
Search for similar documents in the vector store or retrieve all documents if no query is provided.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
vector_store = self.build_vector_store()
|
vector_store = self.build_vector_store()
|
||||||
|
|
||||||
|
|
@ -239,8 +231,8 @@ class OpenSearchVectorStoreComponent(LCVectorStoreComponent):
|
||||||
raise ValueError(error_message)
|
raise ValueError(error_message)
|
||||||
|
|
||||||
def search_documents(self) -> list[Data]:
|
def search_documents(self) -> list[Data]:
|
||||||
"""
|
"""Search for documents in the vector store based on the search input.
|
||||||
Search for documents in the vector store based on the search input.
|
|
||||||
If no search input is provided, retrieve all documents.
|
If no search input is provided, retrieve all documents.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,7 @@ from langflow.schema import Data
|
||||||
|
|
||||||
|
|
||||||
class RedisVectorStoreComponent(LCVectorStoreComponent):
|
class RedisVectorStoreComponent(LCVectorStoreComponent):
|
||||||
"""
|
"""A custom component for implementing a Vector Store using Redis."""
|
||||||
A custom component for implementing a Vector Store using Redis.
|
|
||||||
"""
|
|
||||||
|
|
||||||
display_name: str = "Redis"
|
display_name: str = "Redis"
|
||||||
description: str = "Implementation of Vector Store using Redis"
|
description: str = "Implementation of Vector Store using Redis"
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class VectaraVectorStoreComponent(LCVectorStoreComponent):
|
class VectaraVectorStoreComponent(LCVectorStoreComponent):
|
||||||
"""
|
"""Vectara Vector Store with search capabilities."""
|
||||||
Vectara Vector Store with search capabilities
|
|
||||||
"""
|
|
||||||
|
|
||||||
display_name: str = "Vectara"
|
display_name: str = "Vectara"
|
||||||
description: str = "Vectara Vector Store with search capabilities"
|
description: str = "Vectara Vector Store with search capabilities"
|
||||||
|
|
@ -53,9 +51,7 @@ class VectaraVectorStoreComponent(LCVectorStoreComponent):
|
||||||
|
|
||||||
@check_cached_vector_store
|
@check_cached_vector_store
|
||||||
def build_vector_store(self) -> "Vectara":
|
def build_vector_store(self) -> "Vectara":
|
||||||
"""
|
"""Builds the Vectara object."""
|
||||||
Builds the Vectara object.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
from langchain_community.vectorstores import Vectara
|
from langchain_community.vectorstores import Vectara
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
|
|
@ -72,9 +68,7 @@ class VectaraVectorStoreComponent(LCVectorStoreComponent):
|
||||||
return vectara
|
return vectara
|
||||||
|
|
||||||
def _add_documents_to_vector_store(self, vector_store: "Vectara") -> None:
|
def _add_documents_to_vector_store(self, vector_store: "Vectara") -> None:
|
||||||
"""
|
"""Adds documents to the Vector Store."""
|
||||||
Adds documents to the Vector Store.
|
|
||||||
"""
|
|
||||||
if not self.ingest_data:
|
if not self.ingest_data:
|
||||||
self.status = "No documents to add to Vectara"
|
self.status = "No documents to add to Vectara"
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -58,14 +58,10 @@ def imports_key(*args, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
class CodeParser:
|
class CodeParser:
|
||||||
"""
|
"""A parser for Python source code, extracting code details."""
|
||||||
A parser for Python source code, extracting code details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, code: str | type) -> None:
|
def __init__(self, code: str | type) -> None:
|
||||||
"""
|
"""Initializes the parser with the provided code."""
|
||||||
Initializes the parser with the provided code.
|
|
||||||
"""
|
|
||||||
self.cache: TTLCache = TTLCache(maxsize=1024, ttl=60)
|
self.cache: TTLCache = TTLCache(maxsize=1024, ttl=60)
|
||||||
if isinstance(code, type):
|
if isinstance(code, type):
|
||||||
if not inspect.isclass(code):
|
if not inspect.isclass(code):
|
||||||
|
|
@ -89,8 +85,8 @@ class CodeParser:
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_tree(self):
|
def get_tree(self):
|
||||||
"""
|
"""Parses the provided code to validate its syntax.
|
||||||
Parses the provided code to validate its syntax.
|
|
||||||
It tries to parse the code into an abstract syntax tree (AST).
|
It tries to parse the code into an abstract syntax tree (AST).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -104,17 +100,12 @@ class CodeParser:
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
def parse_node(self, node: ast.stmt | ast.AST) -> None:
|
def parse_node(self, node: ast.stmt | ast.AST) -> None:
|
||||||
"""
|
"""Parses an AST node and updates the data dictionary with the relevant information."""
|
||||||
Parses an AST node and updates the data
|
|
||||||
dictionary with the relevant information.
|
|
||||||
"""
|
|
||||||
if handler := self.handlers.get(type(node)):
|
if handler := self.handlers.get(type(node)):
|
||||||
handler(node) # type: ignore[operator]
|
handler(node) # type: ignore[operator]
|
||||||
|
|
||||||
def parse_imports(self, node: ast.Import | ast.ImportFrom) -> None:
|
def parse_imports(self, node: ast.Import | ast.ImportFrom) -> None:
|
||||||
"""
|
"""Extracts "imports" from the code, including aliases."""
|
||||||
Extracts "imports" from the code, including aliases.
|
|
||||||
"""
|
|
||||||
if isinstance(node, ast.Import):
|
if isinstance(node, ast.Import):
|
||||||
for alias in node.names:
|
for alias in node.names:
|
||||||
if alias.asname:
|
if alias.asname:
|
||||||
|
|
@ -129,15 +120,11 @@ class CodeParser:
|
||||||
self.data["imports"].append((node.module, alias.name))
|
self.data["imports"].append((node.module, alias.name))
|
||||||
|
|
||||||
def parse_functions(self, node: ast.FunctionDef) -> None:
|
def parse_functions(self, node: ast.FunctionDef) -> None:
|
||||||
"""
|
"""Extracts "functions" from the code."""
|
||||||
Extracts "functions" from the code.
|
|
||||||
"""
|
|
||||||
self.data["functions"].append(self.parse_callable_details(node))
|
self.data["functions"].append(self.parse_callable_details(node))
|
||||||
|
|
||||||
def parse_arg(self, arg, default):
|
def parse_arg(self, arg, default):
|
||||||
"""
|
"""Parses an argument and its default value."""
|
||||||
Parses an argument and its default value.
|
|
||||||
"""
|
|
||||||
arg_dict = {"name": arg.arg, "default": default}
|
arg_dict = {"name": arg.arg, "default": default}
|
||||||
if arg.annotation:
|
if arg.annotation:
|
||||||
arg_dict["type"] = ast.unparse(arg.annotation)
|
arg_dict["type"] = ast.unparse(arg.annotation)
|
||||||
|
|
@ -145,7 +132,8 @@ class CodeParser:
|
||||||
|
|
||||||
# @cachedmethod(operator.attrgetter("cache"))
|
# @cachedmethod(operator.attrgetter("cache"))
|
||||||
def construct_eval_env(self, return_type_str: str, imports) -> dict:
|
def construct_eval_env(self, return_type_str: str, imports) -> dict:
|
||||||
"""
|
"""Constructs an evaluation environment.
|
||||||
|
|
||||||
Constructs an evaluation environment with the necessary imports for the return type,
|
Constructs an evaluation environment with the necessary imports for the return type,
|
||||||
taking into account module aliases.
|
taking into account module aliases.
|
||||||
"""
|
"""
|
||||||
|
|
@ -166,9 +154,7 @@ class CodeParser:
|
||||||
return eval_env
|
return eval_env
|
||||||
|
|
||||||
def parse_callable_details(self, node: ast.FunctionDef) -> dict[str, Any]:
|
def parse_callable_details(self, node: ast.FunctionDef) -> dict[str, Any]:
|
||||||
"""
|
"""Extracts details from a single function or method node."""
|
||||||
Extracts details from a single function or method node.
|
|
||||||
"""
|
|
||||||
return_type = None
|
return_type = None
|
||||||
if node.returns:
|
if node.returns:
|
||||||
return_type_str = ast.unparse(node.returns)
|
return_type_str = ast.unparse(node.returns)
|
||||||
|
|
@ -190,9 +176,7 @@ class CodeParser:
|
||||||
return func.model_dump()
|
return func.model_dump()
|
||||||
|
|
||||||
def parse_function_args(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
def parse_function_args(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
||||||
"""
|
"""Parses the arguments of a function or method node."""
|
||||||
Parses the arguments of a function or method node.
|
|
||||||
"""
|
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
args += self.parse_positional_args(node)
|
args += self.parse_positional_args(node)
|
||||||
|
|
@ -205,9 +189,7 @@ class CodeParser:
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def parse_positional_args(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
def parse_positional_args(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
||||||
"""
|
"""Parses the positional arguments of a function or method node."""
|
||||||
Parses the positional arguments of a function or method node.
|
|
||||||
"""
|
|
||||||
num_args = len(node.args.args)
|
num_args = len(node.args.args)
|
||||||
num_defaults = len(node.args.defaults)
|
num_defaults = len(node.args.defaults)
|
||||||
num_missing_defaults = num_args - num_defaults
|
num_missing_defaults = num_args - num_defaults
|
||||||
|
|
@ -222,9 +204,7 @@ class CodeParser:
|
||||||
return list(starmap(self.parse_arg, zip(node.args.args, defaults, strict=True)))
|
return list(starmap(self.parse_arg, zip(node.args.args, defaults, strict=True)))
|
||||||
|
|
||||||
def parse_varargs(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
def parse_varargs(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
||||||
"""
|
"""Parses the *args argument of a function or method node."""
|
||||||
Parses the *args argument of a function or method node.
|
|
||||||
"""
|
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
if node.args.vararg:
|
if node.args.vararg:
|
||||||
|
|
@ -233,9 +213,7 @@ class CodeParser:
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def parse_keyword_args(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
def parse_keyword_args(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
||||||
"""
|
"""Parses the keyword-only arguments of a function or method node."""
|
||||||
Parses the keyword-only arguments of a function or method node.
|
|
||||||
"""
|
|
||||||
kw_defaults = [None] * (len(node.args.kwonlyargs) - len(node.args.kw_defaults)) + [
|
kw_defaults = [None] * (len(node.args.kwonlyargs) - len(node.args.kw_defaults)) + [
|
||||||
ast.unparse(default) if default else None for default in node.args.kw_defaults
|
ast.unparse(default) if default else None for default in node.args.kw_defaults
|
||||||
]
|
]
|
||||||
|
|
@ -243,9 +221,7 @@ class CodeParser:
|
||||||
return list(starmap(self.parse_arg, zip(node.args.kwonlyargs, kw_defaults, strict=True)))
|
return list(starmap(self.parse_arg, zip(node.args.kwonlyargs, kw_defaults, strict=True)))
|
||||||
|
|
||||||
def parse_kwargs(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
def parse_kwargs(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
|
||||||
"""
|
"""Parses the **kwargs argument of a function or method node."""
|
||||||
Parses the **kwargs argument of a function or method node.
|
|
||||||
"""
|
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
if node.args.kwarg:
|
if node.args.kwarg:
|
||||||
|
|
@ -254,15 +230,11 @@ class CodeParser:
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def parse_function_body(self, node: ast.FunctionDef) -> list[str]:
|
def parse_function_body(self, node: ast.FunctionDef) -> list[str]:
|
||||||
"""
|
"""Parses the body of a function or method node."""
|
||||||
Parses the body of a function or method node.
|
|
||||||
"""
|
|
||||||
return [ast.unparse(line) for line in node.body]
|
return [ast.unparse(line) for line in node.body]
|
||||||
|
|
||||||
def parse_return_statement(self, node: ast.FunctionDef) -> bool:
|
def parse_return_statement(self, node: ast.FunctionDef) -> bool:
|
||||||
"""
|
"""Parses the return statement of a function or method node, including nested returns."""
|
||||||
Parses the return statement of a function or method node, including nested returns.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def has_return(node):
|
def has_return(node):
|
||||||
if isinstance(node, ast.Return):
|
if isinstance(node, ast.Return):
|
||||||
|
|
@ -284,20 +256,14 @@ class CodeParser:
|
||||||
return any(has_return(child) for child in node.body)
|
return any(has_return(child) for child in node.body)
|
||||||
|
|
||||||
def parse_assign(self, stmt):
|
def parse_assign(self, stmt):
|
||||||
"""
|
"""Parses an Assign statement and returns a dictionary with the target's name and value."""
|
||||||
Parses an Assign statement and returns a dictionary
|
|
||||||
with the target's name and value.
|
|
||||||
"""
|
|
||||||
for target in stmt.targets:
|
for target in stmt.targets:
|
||||||
if isinstance(target, ast.Name):
|
if isinstance(target, ast.Name):
|
||||||
return {"name": target.id, "value": ast.unparse(stmt.value)}
|
return {"name": target.id, "value": ast.unparse(stmt.value)}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def parse_ann_assign(self, stmt):
|
def parse_ann_assign(self, stmt):
|
||||||
"""
|
"""Parses an AnnAssign statement and returns a dictionary with the target's name, value, and annotation."""
|
||||||
Parses an AnnAssign statement and returns a dictionary
|
|
||||||
with the target's name, value, and annotation.
|
|
||||||
"""
|
|
||||||
if isinstance(stmt.target, ast.Name):
|
if isinstance(stmt.target, ast.Name):
|
||||||
return {
|
return {
|
||||||
"name": stmt.target.id,
|
"name": stmt.target.id,
|
||||||
|
|
@ -307,17 +273,15 @@ class CodeParser:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def parse_function_def(self, stmt):
|
def parse_function_def(self, stmt):
|
||||||
"""
|
"""Parse a FunctionDef statement.
|
||||||
Parses a FunctionDef statement and returns the parsed
|
|
||||||
method and a boolean indicating if it's an __init__ method.
|
Parse a FunctionDef statement and return the parsed method and a boolean indicating if it's an __init__ method.
|
||||||
"""
|
"""
|
||||||
method = self.parse_callable_details(stmt)
|
method = self.parse_callable_details(stmt)
|
||||||
return (method, True) if stmt.name == "__init__" else (method, False)
|
return (method, True) if stmt.name == "__init__" else (method, False)
|
||||||
|
|
||||||
def get_base_classes(self):
|
def get_base_classes(self):
|
||||||
"""
|
"""Returns the base classes of the custom component class."""
|
||||||
Returns the base classes of the custom component class.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
bases = self.execute_and_inspect_classes(self.code)
|
bases = self.execute_and_inspect_classes(self.code)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -327,9 +291,7 @@ class CodeParser:
|
||||||
return bases
|
return bases
|
||||||
|
|
||||||
def parse_classes(self, node: ast.ClassDef) -> None:
|
def parse_classes(self, node: ast.ClassDef) -> None:
|
||||||
"""
|
"""Extracts "classes" from the code, including inheritance and init methods."""
|
||||||
Extracts "classes" from the code, including inheritance and init methods.
|
|
||||||
"""
|
|
||||||
bases = self.get_base_classes()
|
bases = self.get_base_classes()
|
||||||
nodes = []
|
nodes = []
|
||||||
for base in bases:
|
for base in bases:
|
||||||
|
|
@ -373,9 +335,7 @@ class CodeParser:
|
||||||
class_details.methods.append(method)
|
class_details.methods.append(method)
|
||||||
|
|
||||||
def parse_global_vars(self, node: ast.Assign) -> None:
|
def parse_global_vars(self, node: ast.Assign) -> None:
|
||||||
"""
|
"""Extracts global variables from the code."""
|
||||||
Extracts global variables from the code.
|
|
||||||
"""
|
|
||||||
global_var = {
|
global_var = {
|
||||||
"targets": [t.id if hasattr(t, "id") else ast.dump(t) for t in node.targets],
|
"targets": [t.id if hasattr(t, "id") else ast.dump(t) for t in node.targets],
|
||||||
"value": ast.unparse(node.value),
|
"value": ast.unparse(node.value),
|
||||||
|
|
@ -394,9 +354,7 @@ class CodeParser:
|
||||||
return bases
|
return bases
|
||||||
|
|
||||||
def parse_code(self) -> dict[str, Any]:
|
def parse_code(self) -> dict[str, Any]:
|
||||||
"""
|
"""Runs all parsing operations and returns the resulting data."""
|
||||||
Runs all parsing operations and returns the resulting data.
|
|
||||||
"""
|
|
||||||
tree = self.get_tree()
|
tree = self.get_tree()
|
||||||
|
|
||||||
for node in ast.walk(tree):
|
for node in ast.walk(tree):
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,7 @@ class BaseComponent:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_template_config(component):
|
def get_template_config(component):
|
||||||
"""
|
"""Gets the template configuration for the custom component itself."""
|
||||||
Gets the template configuration for the custom component itself.
|
|
||||||
"""
|
|
||||||
template_config = {}
|
template_config = {}
|
||||||
|
|
||||||
for attribute, func in ATTR_FUNC_MAPPING.items():
|
for attribute, func in ATTR_FUNC_MAPPING.items():
|
||||||
|
|
@ -87,8 +85,7 @@ class BaseComponent:
|
||||||
return template_config
|
return template_config
|
||||||
|
|
||||||
def build_template_config(self) -> dict:
|
def build_template_config(self) -> dict:
|
||||||
"""
|
"""Builds the template configuration for the custom component.
|
||||||
Builds the template configuration for the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A dictionary representing the template configuration.
|
A dictionary representing the template configuration.
|
||||||
|
|
|
||||||
|
|
@ -170,8 +170,7 @@ class Component(CustomComponent):
|
||||||
raise ValueError(msg) from e
|
raise ValueError(msg) from e
|
||||||
|
|
||||||
def set(self, **kwargs):
|
def set(self, **kwargs):
|
||||||
"""
|
"""Connects the component to other components or sets parameters and attributes.
|
||||||
Connects the component to other components or sets parameters and attributes.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs: Keyword arguments representing the connections, parameters, and attributes.
|
**kwargs: Keyword arguments representing the connections, parameters, and attributes.
|
||||||
|
|
@ -187,20 +186,15 @@ class Component(CustomComponent):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def list_inputs(self):
|
def list_inputs(self):
|
||||||
"""
|
"""Returns a list of input names."""
|
||||||
Returns a list of input names.
|
|
||||||
"""
|
|
||||||
return [_input.name for _input in self.inputs]
|
return [_input.name for _input in self.inputs]
|
||||||
|
|
||||||
def list_outputs(self):
|
def list_outputs(self):
|
||||||
"""
|
"""Returns a list of output names."""
|
||||||
Returns a list of output names.
|
|
||||||
"""
|
|
||||||
return [_output.name for _output in self._outputs_map.values()]
|
return [_output.name for _output in self._outputs_map.values()]
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
"""
|
"""Executes the component's logic and returns the result.
|
||||||
Executes the component's logic and returns the result.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The result of executing the component's logic.
|
The result of executing the component's logic.
|
||||||
|
|
@ -208,8 +202,7 @@ class Component(CustomComponent):
|
||||||
return await self._run()
|
return await self._run()
|
||||||
|
|
||||||
def set_vertex(self, vertex: Vertex):
|
def set_vertex(self, vertex: Vertex):
|
||||||
"""
|
"""Sets the vertex for the component.
|
||||||
Sets the vertex for the component.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vertex (Vertex): The vertex to set.
|
vertex (Vertex): The vertex to set.
|
||||||
|
|
@ -220,8 +213,7 @@ class Component(CustomComponent):
|
||||||
self._vertex = vertex
|
self._vertex = vertex
|
||||||
|
|
||||||
def get_input(self, name: str) -> Any:
|
def get_input(self, name: str) -> Any:
|
||||||
"""
|
"""Retrieves the value of the input with the specified name.
|
||||||
Retrieves the value of the input with the specified name.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The name of the input.
|
name (str): The name of the input.
|
||||||
|
|
@ -238,8 +230,7 @@ class Component(CustomComponent):
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
def get_output(self, name: str) -> Any:
|
def get_output(self, name: str) -> Any:
|
||||||
"""
|
"""Retrieves the output with the specified name.
|
||||||
Retrieves the output with the specified name.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The name of the output to retrieve.
|
name (str): The name of the output to retrieve.
|
||||||
|
|
@ -271,8 +262,7 @@ class Component(CustomComponent):
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
def map_outputs(self, outputs: list[Output]):
|
def map_outputs(self, outputs: list[Output]):
|
||||||
"""
|
"""Maps the given list of outputs to the component.
|
||||||
Maps the given list of outputs to the component.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
outputs (List[Output]): The list of outputs to be mapped.
|
outputs (List[Output]): The list of outputs to be mapped.
|
||||||
|
|
@ -292,8 +282,7 @@ class Component(CustomComponent):
|
||||||
self._outputs_map[output.name] = deepcopy(output)
|
self._outputs_map[output.name] = deepcopy(output)
|
||||||
|
|
||||||
def map_inputs(self, inputs: list[InputTypes]):
|
def map_inputs(self, inputs: list[InputTypes]):
|
||||||
"""
|
"""Maps the given inputs to the component.
|
||||||
Maps the given inputs to the component.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
inputs (List[InputTypes]): A list of InputTypes objects representing the inputs.
|
inputs (List[InputTypes]): A list of InputTypes objects representing the inputs.
|
||||||
|
|
@ -309,8 +298,7 @@ class Component(CustomComponent):
|
||||||
self._inputs[input_.name] = deepcopy(input_)
|
self._inputs[input_.name] = deepcopy(input_)
|
||||||
|
|
||||||
def validate(self, params: dict):
|
def validate(self, params: dict):
|
||||||
"""
|
"""Validates the component parameters.
|
||||||
Validates the component parameters.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
params (dict): A dictionary containing the component parameters.
|
params (dict): A dictionary containing the component parameters.
|
||||||
|
|
@ -377,10 +365,10 @@ class Component(CustomComponent):
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def _find_matching_output_method(self, input_name: str, value: Component):
|
def _find_matching_output_method(self, input_name: str, value: Component):
|
||||||
"""
|
"""Find the output method from the given component and input name.
|
||||||
|
|
||||||
Find the output method from the given component (`value`) that matches the specified input (`input_name`)
|
Find the output method from the given component (`value`) that matches the specified input (`input_name`)
|
||||||
in the current component.
|
in the current component.
|
||||||
|
|
||||||
This method searches through all outputs of the provided component to find outputs whose types match
|
This method searches through all outputs of the provided component to find outputs whose types match
|
||||||
the input types of the specified input in the current component. If exactly one matching output is found,
|
the input types of the specified input in the current component. If exactly one matching output is found,
|
||||||
it returns the corresponding method. If multiple matching outputs are found, it raises an error indicating
|
it returns the corresponding method. If multiple matching outputs are found, it raises an error indicating
|
||||||
|
|
@ -788,8 +776,7 @@ class Component(CustomComponent):
|
||||||
return self.repr_value
|
return self.repr_value
|
||||||
|
|
||||||
def build_inputs(self, user_id: str | UUID | None = None):
|
def build_inputs(self, user_id: str | UUID | None = None):
|
||||||
"""
|
"""Builds the inputs for the custom component.
|
||||||
Builds the inputs for the custom component.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user_id (Optional[Union[str, UUID]], optional): The user ID. Defaults to None.
|
user_id (Optional[Union[str, UUID]], optional): The user ID. Defaults to None.
|
||||||
|
|
@ -827,11 +814,11 @@ class Component(CustomComponent):
|
||||||
return "Langflow"
|
return "Langflow"
|
||||||
|
|
||||||
def log(self, message: LoggableType | list[LoggableType], name: str | None = None):
|
def log(self, message: LoggableType | list[LoggableType], name: str | None = None):
|
||||||
"""
|
"""Logs a message.
|
||||||
Logs a message.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message (LoggableType | list[LoggableType]): The message to log.
|
message (LoggableType | list[LoggableType]): The message to log.
|
||||||
|
name (str, optional): The name of the log. Defaults to None.
|
||||||
"""
|
"""
|
||||||
if name is None:
|
if name is None:
|
||||||
name = f"Log {len(self._logs) + 1}"
|
name = f"Log {len(self._logs) + 1}"
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class CustomComponent(BaseComponent):
|
class CustomComponent(BaseComponent):
|
||||||
"""
|
"""Represents a custom component in Langflow.
|
||||||
Represents a custom component in Langflow.
|
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
name (Optional[str]): This attribute helps the frontend apply styles to known components.
|
name (Optional[str]): This attribute helps the frontend apply styles to known components.
|
||||||
|
|
@ -87,8 +86,7 @@ class CustomComponent(BaseComponent):
|
||||||
_tree: dict | None = None
|
_tree: dict | None = None
|
||||||
|
|
||||||
def __init__(self, **data):
|
def __init__(self, **data):
|
||||||
"""
|
"""Initializes a new instance of the CustomComponent class.
|
||||||
Initializes a new instance of the CustomComponent class.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**data: Additional keyword arguments to initialize the custom component.
|
**data: Additional keyword arguments to initialize the custom component.
|
||||||
|
|
@ -196,8 +194,7 @@ class CustomComponent(BaseComponent):
|
||||||
return self.field_order or list(self.field_config.keys())
|
return self.field_order or list(self.field_config.keys())
|
||||||
|
|
||||||
def custom_repr(self):
|
def custom_repr(self):
|
||||||
"""
|
"""Returns the custom representation of the custom component.
|
||||||
Returns the custom representation of the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The custom representation of the custom component.
|
str: The custom representation of the custom component.
|
||||||
|
|
@ -213,8 +210,7 @@ class CustomComponent(BaseComponent):
|
||||||
return self.repr_value
|
return self.repr_value
|
||||||
|
|
||||||
def build_config(self):
|
def build_config(self):
|
||||||
"""
|
"""Builds the configuration for the custom component.
|
||||||
Builds the configuration for the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The configuration for the custom component.
|
dict: The configuration for the custom component.
|
||||||
|
|
@ -232,8 +228,7 @@ class CustomComponent(BaseComponent):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tree(self):
|
def tree(self):
|
||||||
"""
|
"""Gets the code tree of the custom component.
|
||||||
Gets the code tree of the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The code tree of the custom component.
|
dict: The code tree of the custom component.
|
||||||
|
|
@ -241,17 +236,18 @@ class CustomComponent(BaseComponent):
|
||||||
return self.get_code_tree(self._code or "")
|
return self.get_code_tree(self._code or "")
|
||||||
|
|
||||||
def to_data(self, data: Any, keys: list[str] | None = None, silent_errors: bool = False) -> list[Data]:
|
def to_data(self, data: Any, keys: list[str] | None = None, silent_errors: bool = False) -> list[Data]:
|
||||||
"""
|
"""Converts input data into a list of Data objects.
|
||||||
Converts input data into a list of Data objects.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data (Any): The input data to be converted. It can be a single item or a sequence of items.
|
data (Any): The input data to be converted. It can be a single item or a sequence of items.
|
||||||
If the input data is a Langchain Document, text_key and data_key are ignored.
|
If the input data is a Langchain Document, text_key and data_key are ignored.
|
||||||
|
|
||||||
keys (List[str], optional): The keys to access the text and data values in each item.
|
keys (List[str], optional): The keys to access the text and data values in each item.
|
||||||
It should be a list of strings where the first element is the text key and the second element
|
It should be a list of strings where the first element is the text key and the second element
|
||||||
is the data key.
|
is the data key.
|
||||||
Defaults to None, in which case the default keys "text" and "data" are used.
|
Defaults to None, in which case the default keys "text" and "data" are used.
|
||||||
|
silent_errors (bool, optional): Whether to suppress errors when the specified keys are not found
|
||||||
|
in the data.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Data]: A list of Data objects.
|
List[Data]: A list of Data objects.
|
||||||
|
|
@ -303,8 +299,7 @@ class CustomComponent(BaseComponent):
|
||||||
return self._extract_return_type(return_type)
|
return self._extract_return_type(return_type)
|
||||||
|
|
||||||
def create_references_from_data(self, data: list[Data], include_data: bool = False) -> str:
|
def create_references_from_data(self, data: list[Data], include_data: bool = False) -> str:
|
||||||
"""
|
"""Create references from a list of data.
|
||||||
Create references from a list of data.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data (List[dict]): A list of data, where each record is a dictionary.
|
data (List[dict]): A list of data, where each record is a dictionary.
|
||||||
|
|
@ -325,8 +320,7 @@ class CustomComponent(BaseComponent):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_function_entrypoint_args(self) -> list:
|
def get_function_entrypoint_args(self) -> list:
|
||||||
"""
|
"""Gets the arguments of the function entrypoint for the custom component.
|
||||||
Gets the arguments of the function entrypoint for the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list: The arguments of the function entrypoint.
|
list: The arguments of the function entrypoint.
|
||||||
|
|
@ -343,8 +337,7 @@ class CustomComponent(BaseComponent):
|
||||||
return args
|
return args
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The build method for the custom component.
|
dict: The build method for the custom component.
|
||||||
|
|
@ -366,8 +359,7 @@ class CustomComponent(BaseComponent):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_function_entrypoint_return_type(self) -> list[Any]:
|
def get_function_entrypoint_return_type(self) -> list[Any]:
|
||||||
"""
|
"""Gets the return type of the function entrypoint for the custom component.
|
||||||
Gets the return type of the function entrypoint for the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Any]: The return type of the function entrypoint.
|
List[Any]: The return type of the function entrypoint.
|
||||||
|
|
@ -379,8 +371,7 @@ class CustomComponent(BaseComponent):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_main_class_name(self):
|
def get_main_class_name(self):
|
||||||
"""
|
"""Gets the main class name of the custom component.
|
||||||
Gets the main class name of the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The main class name of the custom component.
|
str: The main class name of the custom component.
|
||||||
|
|
@ -403,8 +394,7 @@ class CustomComponent(BaseComponent):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def template_config(self):
|
def template_config(self):
|
||||||
"""
|
"""Gets the template configuration for the custom component.
|
||||||
Gets the template configuration for the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The template configuration for the custom component.
|
dict: The template configuration for the custom component.
|
||||||
|
|
@ -415,8 +405,7 @@ class CustomComponent(BaseComponent):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def variables(self):
|
def variables(self):
|
||||||
"""
|
"""Returns the variable for the current user with the specified name.
|
||||||
Returns the variable for the current user with the specified name.
|
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If the user id is not set.
|
ValueError: If the user id is not set.
|
||||||
|
|
@ -438,8 +427,7 @@ class CustomComponent(BaseComponent):
|
||||||
return get_variable
|
return get_variable
|
||||||
|
|
||||||
def list_key_names(self):
|
def list_key_names(self):
|
||||||
"""
|
"""Lists the names of the variables for the current user.
|
||||||
Lists the names of the variables for the current user.
|
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If the user id is not set.
|
ValueError: If the user id is not set.
|
||||||
|
|
@ -456,8 +444,7 @@ class CustomComponent(BaseComponent):
|
||||||
return variable_service.list_variables(user_id=self.user_id, session=session)
|
return variable_service.list_variables(user_id=self.user_id, session=session)
|
||||||
|
|
||||||
def index(self, value: int = 0):
|
def index(self, value: int = 0):
|
||||||
"""
|
"""Returns a function that returns the value at the given index in the iterable.
|
||||||
Returns a function that returns the value at the given index in the iterable.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
value (int): The index value.
|
value (int): The index value.
|
||||||
|
|
@ -472,8 +459,7 @@ class CustomComponent(BaseComponent):
|
||||||
return get_index
|
return get_index
|
||||||
|
|
||||||
def get_function(self):
|
def get_function(self):
|
||||||
"""
|
"""Gets the function associated with the custom component.
|
||||||
Gets the function associated with the custom component.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Callable: The function associated with the custom component.
|
Callable: The function associated with the custom component.
|
||||||
|
|
@ -515,8 +501,7 @@ class CustomComponent(BaseComponent):
|
||||||
raise ValueError(msg) from e
|
raise ValueError(msg) from e
|
||||||
|
|
||||||
def build(self, *args: Any, **kwargs: Any) -> Any:
|
def build(self, *args: Any, **kwargs: Any) -> Any:
|
||||||
"""
|
"""Builds the custom component.
|
||||||
Builds the custom component.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*args: The positional arguments.
|
*args: The positional arguments.
|
||||||
|
|
@ -528,9 +513,7 @@ class CustomComponent(BaseComponent):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):
|
def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):
|
||||||
"""
|
"""This function is called after the code validation is done."""
|
||||||
This function is called after the code validation is done.
|
|
||||||
"""
|
|
||||||
return update_frontend_node_with_template_values(
|
return update_frontend_node_with_template_values(
|
||||||
frontend_node=new_frontend_node, raw_frontend_node=current_frontend_node
|
frontend_node=new_frontend_node, raw_frontend_node=current_frontend_node
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,7 @@ class StringCompressor:
|
||||||
self.input_string = input_string
|
self.input_string = input_string
|
||||||
|
|
||||||
def compress_string(self):
|
def compress_string(self):
|
||||||
"""
|
"""Compress the initial string and return the compressed data."""
|
||||||
Compress the initial string and return the compressed data.
|
|
||||||
"""
|
|
||||||
# Convert string to bytes
|
# Convert string to bytes
|
||||||
byte_data = self.input_string.encode("utf-8")
|
byte_data = self.input_string.encode("utf-8")
|
||||||
# Compress the bytes
|
# Compress the bytes
|
||||||
|
|
@ -29,9 +27,7 @@ class StringCompressor:
|
||||||
return self.compressed_data
|
return self.compressed_data
|
||||||
|
|
||||||
def decompress_string(self):
|
def decompress_string(self):
|
||||||
"""
|
"""Decompress the compressed data and return the original string."""
|
||||||
Decompress the compressed data and return the original string.
|
|
||||||
"""
|
|
||||||
# Decompress the bytes
|
# Decompress the bytes
|
||||||
decompressed_data = zlib.decompress(self.compressed_data)
|
decompressed_data = zlib.decompress(self.compressed_data)
|
||||||
# Convert bytes back to string
|
# Convert bytes back to string
|
||||||
|
|
@ -44,10 +40,7 @@ class DirectoryReader:
|
||||||
base_path = ""
|
base_path = ""
|
||||||
|
|
||||||
def __init__(self, directory_path, compress_code_field=False):
|
def __init__(self, directory_path, compress_code_field=False):
|
||||||
"""
|
"""Initialize DirectoryReader with a directory path and a flag indicating whether to compress the code."""
|
||||||
Initialize DirectoryReader with a directory path
|
|
||||||
and a flag indicating whether to compress the code.
|
|
||||||
"""
|
|
||||||
self.directory_path = directory_path
|
self.directory_path = directory_path
|
||||||
self.compress_code_field = compress_code_field
|
self.compress_code_field = compress_code_field
|
||||||
|
|
||||||
|
|
@ -61,9 +54,7 @@ class DirectoryReader:
|
||||||
return not self.base_path or fullpath.is_relative_to(self.base_path)
|
return not self.base_path or fullpath.is_relative_to(self.base_path)
|
||||||
|
|
||||||
def is_empty_file(self, file_content):
|
def is_empty_file(self, file_content):
|
||||||
"""
|
"""Check if the file content is empty."""
|
||||||
Check if the file content is empty.
|
|
||||||
"""
|
|
||||||
return len(file_content.strip()) == 0
|
return len(file_content.strip()) == 0
|
||||||
|
|
||||||
def filter_loaded_components(self, data: dict, with_errors: bool) -> dict:
|
def filter_loaded_components(self, data: dict, with_errors: bool) -> dict:
|
||||||
|
|
@ -86,9 +77,7 @@ class DirectoryReader:
|
||||||
return {"menu": filtered}
|
return {"menu": filtered}
|
||||||
|
|
||||||
def validate_code(self, file_content):
|
def validate_code(self, file_content):
|
||||||
"""
|
"""Validate the Python code by trying to parse it with ast.parse."""
|
||||||
Validate the Python code by trying to parse it with ast.parse.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
ast.parse(file_content)
|
ast.parse(file_content)
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
|
|
@ -96,15 +85,11 @@ class DirectoryReader:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def validate_build(self, file_content):
|
def validate_build(self, file_content):
|
||||||
"""
|
"""Check if the file content contains a function named 'build'."""
|
||||||
Check if the file content contains a function named 'build'.
|
|
||||||
"""
|
|
||||||
return "def build" in file_content
|
return "def build" in file_content
|
||||||
|
|
||||||
def read_file_content(self, file_path):
|
def read_file_content(self, file_path):
|
||||||
"""
|
"""Read and return the content of a file."""
|
||||||
Read and return the content of a file.
|
|
||||||
"""
|
|
||||||
_file_path = Path(file_path)
|
_file_path = Path(file_path)
|
||||||
if not _file_path.is_file():
|
if not _file_path.is_file():
|
||||||
return None
|
return None
|
||||||
|
|
@ -119,9 +104,7 @@ class DirectoryReader:
|
||||||
return f.read().decode("utf-8")
|
return f.read().decode("utf-8")
|
||||||
|
|
||||||
def get_files(self):
|
def get_files(self):
|
||||||
"""
|
"""Walk through the directory path and return a list of all .py files."""
|
||||||
Walk through the directory path and return a list of all .py files.
|
|
||||||
"""
|
|
||||||
if not (safe_path := self.get_safe_path()):
|
if not (safe_path := self.get_safe_path()):
|
||||||
msg = f"The path needs to start with '{self.base_path}'."
|
msg = f"The path needs to start with '{self.base_path}'."
|
||||||
raise CustomComponentPathValueError(msg)
|
raise CustomComponentPathValueError(msg)
|
||||||
|
|
@ -143,19 +126,14 @@ class DirectoryReader:
|
||||||
return file_list
|
return file_list
|
||||||
|
|
||||||
def find_menu(self, response, menu_name):
|
def find_menu(self, response, menu_name):
|
||||||
"""
|
"""Find and return a menu by its name in the response."""
|
||||||
Find and return a menu by its name in the response.
|
|
||||||
"""
|
|
||||||
return next(
|
return next(
|
||||||
(menu for menu in response["menu"] if menu["name"] == menu_name),
|
(menu for menu in response["menu"] if menu["name"] == menu_name),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _is_type_hint_imported(self, type_hint_name: str, code: str) -> bool:
|
def _is_type_hint_imported(self, type_hint_name: str, code: str) -> bool:
|
||||||
"""
|
"""Check if a specific type hint is imported from the typing module in the given code."""
|
||||||
Check if a specific type hint is imported
|
|
||||||
from the typing module in the given code.
|
|
||||||
"""
|
|
||||||
module = ast.parse(code)
|
module = ast.parse(code)
|
||||||
|
|
||||||
return any(
|
return any(
|
||||||
|
|
@ -166,10 +144,7 @@ class DirectoryReader:
|
||||||
)
|
)
|
||||||
|
|
||||||
def _is_type_hint_used_in_args(self, type_hint_name: str, code: str) -> bool:
|
def _is_type_hint_used_in_args(self, type_hint_name: str, code: str) -> bool:
|
||||||
"""
|
"""Check if a specific type hint is used in the function definitions within the given code."""
|
||||||
Check if a specific type hint is used in the
|
|
||||||
function definitions within the given code.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
module = ast.parse(code)
|
module = ast.parse(code)
|
||||||
|
|
||||||
|
|
@ -184,9 +159,7 @@ class DirectoryReader:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _is_type_hint_in_arg_annotation(self, annotation, type_hint_name: str) -> bool:
|
def _is_type_hint_in_arg_annotation(self, annotation, type_hint_name: str) -> bool:
|
||||||
"""
|
"""Helper function to check if a type hint exists in an annotation."""
|
||||||
Helper function to check if a type hint exists in an annotation.
|
|
||||||
"""
|
|
||||||
return (
|
return (
|
||||||
annotation is not None
|
annotation is not None
|
||||||
and isinstance(annotation, ast.Subscript)
|
and isinstance(annotation, ast.Subscript)
|
||||||
|
|
@ -195,9 +168,7 @@ class DirectoryReader:
|
||||||
)
|
)
|
||||||
|
|
||||||
def is_type_hint_used_but_not_imported(self, type_hint_name: str, code: str) -> bool:
|
def is_type_hint_used_but_not_imported(self, type_hint_name: str, code: str) -> bool:
|
||||||
"""
|
"""Check if a type hint is used but not imported in the given code."""
|
||||||
Check if a type hint is used but not imported in the given code.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
return self._is_type_hint_used_in_args(type_hint_name, code) and not self._is_type_hint_imported(
|
return self._is_type_hint_used_in_args(type_hint_name, code) and not self._is_type_hint_imported(
|
||||||
type_hint_name, code
|
type_hint_name, code
|
||||||
|
|
@ -208,10 +179,7 @@ class DirectoryReader:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def process_file(self, file_path):
|
def process_file(self, file_path):
|
||||||
"""
|
"""Process a file by validating its content and returning the result and content/error message."""
|
||||||
Process a file by validating its content and
|
|
||||||
returning the result and content/error message.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
file_content = self.read_file_content(file_path)
|
file_content = self.read_file_content(file_path)
|
||||||
except Exception: # noqa: BLE001
|
except Exception: # noqa: BLE001
|
||||||
|
|
@ -236,10 +204,7 @@ class DirectoryReader:
|
||||||
return True, file_content
|
return True, file_content
|
||||||
|
|
||||||
def build_component_menu_list(self, file_paths):
|
def build_component_menu_list(self, file_paths):
|
||||||
"""
|
"""Build a list of menus with their components from the .py files in the directory."""
|
||||||
Build a list of menus with their components
|
|
||||||
from the .py files in the directory.
|
|
||||||
"""
|
|
||||||
response = {"menu": []}
|
response = {"menu": []}
|
||||||
logger.debug("-------------------- Building component menu list --------------------")
|
logger.debug("-------------------- Building component menu list --------------------")
|
||||||
|
|
||||||
|
|
@ -369,9 +334,7 @@ class DirectoryReader:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_output_types_from_code(code: str) -> list:
|
def get_output_types_from_code(code: str) -> list:
|
||||||
"""
|
"""Get the output types from the code."""
|
||||||
Get the output types from the code.
|
|
||||||
"""
|
|
||||||
custom_component = Component(_code=code)
|
custom_component = Component(_code=code)
|
||||||
types_list = custom_component.get_function_entrypoint_return_type
|
types_list = custom_component.get_function_entrypoint_return_type
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ def build_valid_menu(valid_components):
|
||||||
|
|
||||||
|
|
||||||
def build_and_validate_all_files(reader: DirectoryReader, file_list):
|
def build_and_validate_all_files(reader: DirectoryReader, file_list):
|
||||||
"""Build and validate all files"""
|
"""Build and validate all files."""
|
||||||
data = reader.build_component_menu_list(file_list)
|
data = reader.build_component_menu_list(file_list)
|
||||||
|
|
||||||
valid_components = reader.filter_loaded_components(data=data, with_errors=False)
|
valid_components = reader.filter_loaded_components(data=data, with_errors=False)
|
||||||
|
|
@ -52,7 +52,7 @@ def build_and_validate_all_files(reader: DirectoryReader, file_list):
|
||||||
|
|
||||||
|
|
||||||
async def abuild_and_validate_all_files(reader: DirectoryReader, file_list):
|
async def abuild_and_validate_all_files(reader: DirectoryReader, file_list):
|
||||||
"""Build and validate all files"""
|
"""Build and validate all files."""
|
||||||
data = await reader.abuild_component_menu_list(file_list)
|
data = await reader.abuild_component_menu_list(file_list)
|
||||||
|
|
||||||
valid_components = reader.filter_loaded_components(data=data, with_errors=False)
|
valid_components = reader.filter_loaded_components(data=data, with_errors=False)
|
||||||
|
|
@ -62,14 +62,14 @@ async def abuild_and_validate_all_files(reader: DirectoryReader, file_list):
|
||||||
|
|
||||||
|
|
||||||
def load_files_from_path(path: str):
|
def load_files_from_path(path: str):
|
||||||
"""Load all files from a given path"""
|
"""Load all files from a given path."""
|
||||||
reader = DirectoryReader(path, False)
|
reader = DirectoryReader(path, False)
|
||||||
|
|
||||||
return reader.get_files()
|
return reader.get_files()
|
||||||
|
|
||||||
|
|
||||||
def build_custom_component_list_from_path(path: str):
|
def build_custom_component_list_from_path(path: str):
|
||||||
"""Build a list of custom components for the langchain from a given path"""
|
"""Build a list of custom components for the langchain from a given path."""
|
||||||
file_list = load_files_from_path(path)
|
file_list = load_files_from_path(path)
|
||||||
reader = DirectoryReader(path, False)
|
reader = DirectoryReader(path, False)
|
||||||
|
|
||||||
|
|
@ -82,7 +82,7 @@ def build_custom_component_list_from_path(path: str):
|
||||||
|
|
||||||
|
|
||||||
async def abuild_custom_component_list_from_path(path: str):
|
async def abuild_custom_component_list_from_path(path: str):
|
||||||
"""Build a list of custom components for the langchain from a given path"""
|
"""Build a list of custom components for the langchain from a given path."""
|
||||||
file_list = load_files_from_path(path)
|
file_list = load_files_from_path(path)
|
||||||
reader = DirectoryReader(path, False)
|
reader = DirectoryReader(path, False)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,6 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
def eval_custom_component_code(code: str) -> type["CustomComponent"]:
|
def eval_custom_component_code(code: str) -> type["CustomComponent"]:
|
||||||
"""Evaluate custom component code"""
|
"""Evaluate custom component code."""
|
||||||
class_name = validate.extract_class_name(code)
|
class_name = validate.extract_class_name(code)
|
||||||
return validate.create_class(code, class_name)
|
return validate.create_class(code, class_name)
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class ClassCodeDetails(BaseModel):
|
class ClassCodeDetails(BaseModel):
|
||||||
"""
|
"""A dataclass for storing details about a class."""
|
||||||
A dataclass for storing details about a class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
doc: str | None = None
|
doc: str | None = None
|
||||||
|
|
@ -17,9 +15,7 @@ class ClassCodeDetails(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class CallableCodeDetails(BaseModel):
|
class CallableCodeDetails(BaseModel):
|
||||||
"""
|
"""A dataclass for storing details about a callable."""
|
||||||
A dataclass for storing details about a callable.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
doc: str | None = None
|
doc: str | None = None
|
||||||
|
|
@ -30,9 +26,7 @@ class CallableCodeDetails(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class MissingDefault:
|
class MissingDefault:
|
||||||
"""
|
"""A class to represent a missing default value."""
|
||||||
A class to represent a missing default value.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "MISSING"
|
return "MISSING"
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class UpdateBuildConfigError(Exception):
|
||||||
|
|
||||||
|
|
||||||
def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: list[str]):
|
def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: list[str]):
|
||||||
"""Add output types to the frontend node"""
|
"""Add output types to the frontend node."""
|
||||||
for return_type in return_types:
|
for return_type in return_types:
|
||||||
if return_type is None:
|
if return_type is None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -70,7 +70,7 @@ def reorder_fields(frontend_node: CustomComponentFrontendNode, field_order: list
|
||||||
|
|
||||||
|
|
||||||
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(
|
||||||
|
|
@ -90,8 +90,7 @@ def add_base_classes(frontend_node: CustomComponentFrontendNode, return_types: l
|
||||||
|
|
||||||
|
|
||||||
def extract_type_from_optional(field_type):
|
def extract_type_from_optional(field_type):
|
||||||
"""
|
"""Extract the type from a string formatted as "Optional[<type>]".
|
||||||
Extract the type from a string formatted as "Optional[<type>]".
|
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
field_type (str): The string from which to extract the type.
|
field_type (str): The string from which to extract the type.
|
||||||
|
|
@ -106,7 +105,7 @@ def extract_type_from_optional(field_type):
|
||||||
|
|
||||||
|
|
||||||
def get_field_properties(extra_field):
|
def get_field_properties(extra_field):
|
||||||
"""Get the properties of an extra field"""
|
"""Get the properties of an extra field."""
|
||||||
field_name = extra_field["name"]
|
field_name = extra_field["name"]
|
||||||
field_type = extra_field.get("type", "str")
|
field_type = extra_field.get("type", "str")
|
||||||
field_value = extra_field.get("default", "")
|
field_value = extra_field.get("default", "")
|
||||||
|
|
@ -197,7 +196,7 @@ def add_new_custom_field(
|
||||||
|
|
||||||
|
|
||||||
def add_extra_fields(frontend_node, field_config, function_args):
|
def add_extra_fields(frontend_node, field_config, function_args):
|
||||||
"""Add extra fields to the frontend node"""
|
"""Add extra fields to the frontend node."""
|
||||||
if not function_args:
|
if not function_args:
|
||||||
return
|
return
|
||||||
_field_config = field_config.copy()
|
_field_config = field_config.copy()
|
||||||
|
|
@ -240,7 +239,7 @@ def add_extra_fields(frontend_node, field_config, function_args):
|
||||||
|
|
||||||
|
|
||||||
def get_field_dict(field: Input | dict):
|
def get_field_dict(field: Input | dict):
|
||||||
"""Get the field dictionary from a Input or a dict"""
|
"""Get the field dictionary from a Input or a dict."""
|
||||||
if isinstance(field, Input):
|
if isinstance(field, Input):
|
||||||
return dotdict(field.model_dump(by_alias=True, exclude_none=True))
|
return dotdict(field.model_dump(by_alias=True, exclude_none=True))
|
||||||
return field
|
return field
|
||||||
|
|
@ -298,8 +297,7 @@ def run_build_config(
|
||||||
custom_component: CustomComponent,
|
custom_component: CustomComponent,
|
||||||
user_id: str | UUID | None = None,
|
user_id: str | UUID | None = None,
|
||||||
) -> tuple[dict, CustomComponent]:
|
) -> tuple[dict, CustomComponent]:
|
||||||
"""Build the field configuration for a custom component"""
|
"""Build the field configuration for a custom component."""
|
||||||
|
|
||||||
if custom_component._code is None:
|
if custom_component._code is None:
|
||||||
error = "Code is None"
|
error = "Code is None"
|
||||||
elif not isinstance(custom_component._code, str):
|
elif not isinstance(custom_component._code, str):
|
||||||
|
|
@ -392,7 +390,7 @@ def build_custom_component_template(
|
||||||
custom_component: CustomComponent,
|
custom_component: CustomComponent,
|
||||||
user_id: str | UUID | None = None,
|
user_id: str | UUID | None = None,
|
||||||
) -> tuple[dict[str, Any], CustomComponent | Component]:
|
) -> tuple[dict[str, Any], CustomComponent | Component]:
|
||||||
"""Build a custom component template"""
|
"""Build a custom component template."""
|
||||||
try:
|
try:
|
||||||
has_template_config = hasattr(custom_component, "template_config")
|
has_template_config = hasattr(custom_component, "template_config")
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|
@ -516,7 +514,7 @@ def update_field_dict(
|
||||||
update_field_value: Any | None = None,
|
update_field_value: Any | None = None,
|
||||||
call: bool = False,
|
call: bool = False,
|
||||||
):
|
):
|
||||||
"""Update the field dictionary by calling options() or value() if they are callable"""
|
"""Update the field dictionary by calling options() or value() if they are callable."""
|
||||||
if (
|
if (
|
||||||
("real_time_refresh" in field_dict or "refresh_button" in field_dict)
|
("real_time_refresh" in field_dict or "refresh_button" in field_dict)
|
||||||
and any(
|
and any(
|
||||||
|
|
@ -573,7 +571,7 @@ def build_component(component):
|
||||||
|
|
||||||
|
|
||||||
def get_function(code):
|
def get_function(code):
|
||||||
"""Get the function"""
|
"""Get the function."""
|
||||||
function_name = validate.extract_function_name(code)
|
function_name = validate.extract_function_name(code)
|
||||||
|
|
||||||
return validate.create_function(code, function_name)
|
return validate.create_function(code, function_name)
|
||||||
|
|
|
||||||
|
|
@ -218,8 +218,8 @@ class CycleEdge(Edge):
|
||||||
target._has_cycle_edges = True
|
target._has_cycle_edges = True
|
||||||
|
|
||||||
async def honor(self, source: Vertex, target: Vertex) -> None:
|
async def honor(self, source: Vertex, target: Vertex) -> None:
|
||||||
"""
|
"""Fulfills the contract by setting the result of the source vertex to the target vertex's parameter.
|
||||||
Fulfills the contract by setting the result of the source vertex to the target vertex's parameter.
|
|
||||||
If the edge is runnable, the source vertex is run with the message text and the target vertex's
|
If the edge is runnable, the source vertex is run with the message text and the target vertex's
|
||||||
root_field param is set to the
|
root_field param is set to the
|
||||||
result. If the edge is not runnable, the target vertex's parameter is set to the result.
|
result. If the edge is not runnable, the target vertex's parameter is set to the result.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
"""
|
"""This code is adapted from the DVC project.
|
||||||
This code is adapted from the DVC project.
|
|
||||||
|
|
||||||
Original source:
|
Original source:
|
||||||
https://github.com/iterative/dvc/blob/c5bac1c8cfdb2c0f54d52ac61ff754e6f583822a/dvc/dagascii.py
|
https://github.com/iterative/dvc/blob/c5bac1c8cfdb2c0f54d52ac61ff754e6f583822a/dvc/dagascii.py
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,16 @@ class Graph:
|
||||||
user_id: str | None = None,
|
user_id: str | None = None,
|
||||||
log_config: LogConfig | None = None,
|
log_config: LogConfig | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""Initializes a new instance of the Graph class.
|
||||||
Initializes a new instance of the Graph class.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
nodes (List[Dict]): A list of dictionaries representing the vertices of the graph.
|
start: The start component.
|
||||||
edges (List[Dict[str, str]]): A list of dictionaries representing the edges of the graph.
|
end: The end component.
|
||||||
flow_id (Optional[str], optional): The ID of the flow. Defaults to None.
|
flow_id: The ID of the flow. Defaults to None.
|
||||||
|
flow_name: The flow name.
|
||||||
|
description: The graph description.
|
||||||
|
user_id: The user ID.
|
||||||
|
log_config: The log configuration.
|
||||||
"""
|
"""
|
||||||
if log_config:
|
if log_config:
|
||||||
configure(**log_config)
|
configure(**log_config)
|
||||||
|
|
@ -394,8 +397,7 @@ class Graph:
|
||||||
self.define_vertices_lists()
|
self.define_vertices_lists()
|
||||||
|
|
||||||
def get_state(self, name: str) -> Data | None:
|
def get_state(self, name: str) -> Data | None:
|
||||||
"""
|
"""Returns the state of the graph with the given name.
|
||||||
Returns the state of the graph with the given name.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The name of the state.
|
name (str): The name of the state.
|
||||||
|
|
@ -406,8 +408,7 @@ class Graph:
|
||||||
return self.state_manager.get_state(name, run_id=self._run_id)
|
return self.state_manager.get_state(name, run_id=self._run_id)
|
||||||
|
|
||||||
def update_state(self, name: str, record: str | Data, caller: str | None = None) -> None:
|
def update_state(self, name: str, record: str | Data, caller: str | None = None) -> None:
|
||||||
"""
|
"""Updates the state of the graph with the given name.
|
||||||
Updates the state of the graph with the given name.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The name of the state.
|
name (str): The name of the state.
|
||||||
|
|
@ -424,8 +425,7 @@ class Graph:
|
||||||
self.state_manager.update_state(name, record, run_id=self._run_id)
|
self.state_manager.update_state(name, record, run_id=self._run_id)
|
||||||
|
|
||||||
def activate_state_vertices(self, name: str, caller: str):
|
def activate_state_vertices(self, name: str, caller: str):
|
||||||
"""
|
"""Activates the state vertices in the graph with the given name and caller.
|
||||||
Activates the state vertices in the graph with the given name and caller.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The name of the state.
|
name (str): The name of the state.
|
||||||
|
|
@ -474,14 +474,11 @@ class Graph:
|
||||||
)
|
)
|
||||||
|
|
||||||
def reset_activated_vertices(self):
|
def reset_activated_vertices(self):
|
||||||
"""
|
"""Resets the activated vertices in the graph."""
|
||||||
Resets the activated vertices in the graph.
|
|
||||||
"""
|
|
||||||
self.activated_vertices = []
|
self.activated_vertices = []
|
||||||
|
|
||||||
def append_state(self, name: str, record: str | Data, caller: str | None = None) -> None:
|
def append_state(self, name: str, record: str | Data, caller: str | None = None) -> None:
|
||||||
"""
|
"""Appends the state of the graph with the given name.
|
||||||
Appends the state of the graph with the given name.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The name of the state.
|
name (str): The name of the state.
|
||||||
|
|
@ -494,8 +491,7 @@ class Graph:
|
||||||
self.state_manager.append_state(name, record, run_id=self._run_id)
|
self.state_manager.append_state(name, record, run_id=self._run_id)
|
||||||
|
|
||||||
def validate_stream(self):
|
def validate_stream(self):
|
||||||
"""
|
"""Validates the stream configuration of the graph.
|
||||||
Validates the stream configuration of the graph.
|
|
||||||
|
|
||||||
If there are two vertices in the same graph (connected by edges)
|
If there are two vertices in the same graph (connected by edges)
|
||||||
that have `stream=True` or `streaming=True`, raises a `ValueError`.
|
that have `stream=True` or `streaming=True`, raises a `ValueError`.
|
||||||
|
|
@ -523,8 +519,7 @@ class Graph:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_cyclic(self):
|
def is_cyclic(self):
|
||||||
"""
|
"""Check if the graph has any cycles.
|
||||||
Check if the graph has any cycles.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if the graph has any cycles, False otherwise.
|
bool: True if the graph has any cycles, False otherwise.
|
||||||
|
|
@ -540,8 +535,7 @@ class Graph:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def run_id(self):
|
def run_id(self):
|
||||||
"""
|
"""The ID of the current run.
|
||||||
The ID of the current run.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The run ID.
|
str: The run ID.
|
||||||
|
|
@ -555,8 +549,7 @@ class Graph:
|
||||||
return self._run_id
|
return self._run_id
|
||||||
|
|
||||||
def set_run_id(self, run_id: uuid.UUID | None = None):
|
def set_run_id(self, run_id: uuid.UUID | None = None):
|
||||||
"""
|
"""Sets the ID of the current run.
|
||||||
Sets the ID of the current run.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
run_id (str): The run ID.
|
run_id (str): The run ID.
|
||||||
|
|
@ -600,8 +593,7 @@ class Graph:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sorted_vertices_layers(self) -> list[list[str]]:
|
def sorted_vertices_layers(self) -> list[list[str]]:
|
||||||
"""
|
"""The sorted layers of vertices in the graph.
|
||||||
The sorted layers of vertices in the graph.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[List[str]]: The sorted layers of vertices.
|
List[List[str]]: The sorted layers of vertices.
|
||||||
|
|
@ -611,9 +603,7 @@ class Graph:
|
||||||
return self._sorted_vertices_layers
|
return self._sorted_vertices_layers
|
||||||
|
|
||||||
def define_vertices_lists(self):
|
def define_vertices_lists(self):
|
||||||
"""
|
"""Defines the lists of vertices that are inputs, outputs, and have session_id."""
|
||||||
Defines the lists of vertices that are inputs, outputs, and have session_id.
|
|
||||||
"""
|
|
||||||
attributes = ["is_input", "is_output", "has_session_id", "is_state"]
|
attributes = ["is_input", "is_output", "has_session_id", "is_state"]
|
||||||
for vertex in self.vertices:
|
for vertex in self.vertices:
|
||||||
for attribute in attributes:
|
for attribute in attributes:
|
||||||
|
|
@ -645,20 +635,20 @@ class Graph:
|
||||||
session_id: str,
|
session_id: str,
|
||||||
fallback_to_env_vars: bool,
|
fallback_to_env_vars: bool,
|
||||||
) -> list[ResultData | None]:
|
) -> list[ResultData | None]:
|
||||||
"""
|
"""Runs the graph with the given inputs.
|
||||||
Runs the graph with the given inputs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
inputs (Dict[str, str]): The input values for the graph.
|
inputs (Dict[str, str]): The input values for the graph.
|
||||||
input_components (list[str]): The components to run for the inputs.
|
input_components (list[str]): The components to run for the inputs.
|
||||||
|
input_type: (Optional[InputType]): The input type.
|
||||||
outputs (list[str]): The outputs to retrieve from the graph.
|
outputs (list[str]): The outputs to retrieve from the graph.
|
||||||
stream (bool): Whether to stream the results or not.
|
stream (bool): Whether to stream the results or not.
|
||||||
session_id (str): The session ID for the graph.
|
session_id (str): The session ID for the graph.
|
||||||
|
fallback_to_env_vars (bool): Whether to fallback to environment variables.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Optional["ResultData"]]: The outputs of the graph.
|
List[Optional["ResultData"]]: The outputs of the graph.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if input_components and not isinstance(input_components, list):
|
if input_components and not isinstance(input_components, list):
|
||||||
msg = f"Invalid components value: {input_components}. Expected list"
|
msg = f"Invalid components value: {input_components}. Expected list"
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
@ -722,8 +712,7 @@ class Graph:
|
||||||
stream: bool = False,
|
stream: bool = False,
|
||||||
fallback_to_env_vars: bool = False,
|
fallback_to_env_vars: bool = False,
|
||||||
) -> list[RunOutputs]:
|
) -> list[RunOutputs]:
|
||||||
"""
|
"""Run the graph with the given inputs and return the outputs.
|
||||||
Run the graph with the given inputs and return the outputs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
inputs (Dict[str, str]): A dictionary of input values.
|
inputs (Dict[str, str]): A dictionary of input values.
|
||||||
|
|
@ -732,6 +721,7 @@ class Graph:
|
||||||
outputs (Optional[list[str]]): A list of output components.
|
outputs (Optional[list[str]]): A list of output components.
|
||||||
session_id (Optional[str]): The session ID.
|
session_id (Optional[str]): The session ID.
|
||||||
stream (bool): Whether to stream the outputs.
|
stream (bool): Whether to stream the outputs.
|
||||||
|
fallback_to_env_vars (bool): Whether to fallback to environment variables.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[RunOutputs]: A list of RunOutputs objects representing the outputs.
|
List[RunOutputs]: A list of RunOutputs objects representing the outputs.
|
||||||
|
|
@ -773,15 +763,16 @@ class Graph:
|
||||||
stream: bool = False,
|
stream: bool = False,
|
||||||
fallback_to_env_vars: bool = False,
|
fallback_to_env_vars: bool = False,
|
||||||
) -> list[RunOutputs]:
|
) -> list[RunOutputs]:
|
||||||
"""
|
"""Runs the graph with the given inputs.
|
||||||
Runs the graph with the given inputs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
inputs (list[Dict[str, str]]): The input values for the graph.
|
inputs (list[Dict[str, str]]): The input values for the graph.
|
||||||
inputs_components (Optional[list[list[str]]], optional): Components to run for the inputs. Defaults to None.
|
inputs_components (Optional[list[list[str]]], optional): Components to run for the inputs. Defaults to None.
|
||||||
|
types (Optional[list[Optional[InputType]]], optional): The types of the inputs. Defaults to None.
|
||||||
outputs (Optional[list[str]], optional): The outputs to retrieve from the graph. Defaults to None.
|
outputs (Optional[list[str]], optional): The outputs to retrieve from the graph. Defaults to None.
|
||||||
session_id (Optional[str], optional): The session ID for the graph. Defaults to None.
|
session_id (Optional[str], optional): The session ID for the graph. Defaults to None.
|
||||||
stream (bool, optional): Whether to stream the results or not. Defaults to False.
|
stream (bool, optional): Whether to stream the results or not. Defaults to False.
|
||||||
|
fallback_to_env_vars (bool, optional): Whether to fallback to environment variables. Defaults to False.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[RunOutputs]: The outputs of the graph.
|
List[RunOutputs]: The outputs of the graph.
|
||||||
|
|
@ -821,8 +812,7 @@ class Graph:
|
||||||
return vertex_outputs
|
return vertex_outputs
|
||||||
|
|
||||||
def next_vertex_to_build(self):
|
def next_vertex_to_build(self):
|
||||||
"""
|
"""Returns the next vertex to be built.
|
||||||
Returns the next vertex to be built.
|
|
||||||
|
|
||||||
Yields:
|
Yields:
|
||||||
str: The ID of the next vertex to be built.
|
str: The ID of the next vertex to be built.
|
||||||
|
|
@ -831,8 +821,7 @@ class Graph:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def metadata(self):
|
def metadata(self):
|
||||||
"""
|
"""The metadata of the graph.
|
||||||
The metadata of the graph.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The metadata of the graph.
|
dict: The metadata of the graph.
|
||||||
|
|
@ -847,9 +836,7 @@ class Graph:
|
||||||
}
|
}
|
||||||
|
|
||||||
def build_graph_maps(self, edges: list[CycleEdge] | None = None, vertices: list[Vertex] | None = None):
|
def build_graph_maps(self, edges: list[CycleEdge] | None = None, vertices: list[Vertex] | None = None):
|
||||||
"""
|
"""Builds the adjacency maps for the graph."""
|
||||||
Builds the adjacency maps for the graph.
|
|
||||||
"""
|
|
||||||
if edges is None:
|
if edges is None:
|
||||||
edges = self.edges
|
edges = self.edges
|
||||||
|
|
||||||
|
|
@ -862,9 +849,7 @@ class Graph:
|
||||||
self.parent_child_map = self.build_parent_child_map(vertices)
|
self.parent_child_map = self.build_parent_child_map(vertices)
|
||||||
|
|
||||||
def reset_inactivated_vertices(self):
|
def reset_inactivated_vertices(self):
|
||||||
"""
|
"""Resets the inactivated vertices in the graph."""
|
||||||
Resets the inactivated vertices in the graph.
|
|
||||||
"""
|
|
||||||
for vertex_id in self.inactivated_vertices.copy():
|
for vertex_id in self.inactivated_vertices.copy():
|
||||||
self.mark_vertex(vertex_id, "ACTIVE")
|
self.mark_vertex(vertex_id, "ACTIVE")
|
||||||
self.inactivated_vertices = []
|
self.inactivated_vertices = []
|
||||||
|
|
@ -1016,11 +1001,13 @@ class Graph:
|
||||||
flow_name: str | None = None,
|
flow_name: str | None = None,
|
||||||
user_id: str | None = None,
|
user_id: str | None = None,
|
||||||
) -> Graph:
|
) -> Graph:
|
||||||
"""
|
"""Creates a graph from a payload.
|
||||||
Creates a graph from a payload.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
payload (Dict): The payload to create the graph from.`
|
payload: The payload to create the graph from.
|
||||||
|
flow_id: The ID of the flow.
|
||||||
|
flow_name: The flow name.
|
||||||
|
user_id: The user ID.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Graph: The created graph.
|
Graph: The created graph.
|
||||||
|
|
@ -1125,8 +1112,7 @@ class Graph:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def update_vertex_from_another(self, vertex: Vertex, other_vertex: Vertex) -> None:
|
def update_vertex_from_another(self, vertex: Vertex, other_vertex: Vertex) -> None:
|
||||||
"""
|
"""Updates a vertex from another vertex.
|
||||||
Updates a vertex from another vertex.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vertex (Vertex): The vertex to be updated.
|
vertex (Vertex): The vertex to be updated.
|
||||||
|
|
@ -1329,15 +1315,17 @@ class Graph:
|
||||||
fallback_to_env_vars: bool = False,
|
fallback_to_env_vars: bool = False,
|
||||||
event_manager: EventManager | None = None,
|
event_manager: EventManager | None = None,
|
||||||
) -> VertexBuildResult:
|
) -> VertexBuildResult:
|
||||||
"""
|
"""Builds a vertex in the graph.
|
||||||
Builds a vertex in the graph.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
lock (asyncio.Lock): A lock to synchronize access to the graph.
|
|
||||||
set_cache_coro (Coroutine): A coroutine to set the cache.
|
|
||||||
vertex_id (str): The ID of the vertex to build.
|
vertex_id (str): The ID of the vertex to build.
|
||||||
inputs (Optional[Dict[str, str]]): Optional dictionary of inputs for the vertex. Defaults to None.
|
get_cache (GetCache): A coroutine to get the cache.
|
||||||
|
set_cache (SetCache): A coroutine to set the cache.
|
||||||
|
inputs_dict (Optional[Dict[str, str]]): Optional dictionary of inputs for the vertex. Defaults to None.
|
||||||
|
files: (Optional[List[str]]): Optional list of files. Defaults to None.
|
||||||
user_id (Optional[str]): Optional user ID. Defaults to None.
|
user_id (Optional[str]): Optional user ID. Defaults to None.
|
||||||
|
fallback_to_env_vars (bool): Whether to fallback to environment variables. Defaults to False.
|
||||||
|
event_manager (Optional[EventManager]): Optional event manager. Defaults to None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple: A tuple containing the next runnable vertices, top level vertices, result dictionary,
|
Tuple: A tuple containing the next runnable vertices, top level vertices, result dictionary,
|
||||||
|
|
@ -1448,7 +1436,6 @@ class Graph:
|
||||||
|
|
||||||
async def process(self, fallback_to_env_vars: bool, start_component_id: str | None = None) -> Graph:
|
async def process(self, fallback_to_env_vars: bool, start_component_id: str | None = None) -> Graph:
|
||||||
"""Processes the graph with vertices in each layer run in parallel."""
|
"""Processes the graph with vertices in each layer run in parallel."""
|
||||||
|
|
||||||
first_layer = self.sort_vertices(start_component_id=start_component_id)
|
first_layer = self.sort_vertices(start_component_id=start_component_id)
|
||||||
vertex_task_run_count: dict[str, int] = {}
|
vertex_task_run_count: dict[str, int] = {}
|
||||||
to_process = deque(first_layer)
|
to_process = deque(first_layer)
|
||||||
|
|
@ -1554,8 +1541,7 @@ class Graph:
|
||||||
return list(set(results))
|
return list(set(results))
|
||||||
|
|
||||||
def topological_sort(self) -> list[Vertex]:
|
def topological_sort(self) -> list[Vertex]:
|
||||||
"""
|
"""Performs a topological sort of the vertices in the graph.
|
||||||
Performs a topological sort of the vertices in the graph.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Vertex]: A list of vertices in topological order.
|
List[Vertex]: A list of vertices in topological order.
|
||||||
|
|
@ -2019,8 +2005,7 @@ class Graph:
|
||||||
return self.run_manager.is_vertex_runnable(vertex_id, is_active)
|
return self.run_manager.is_vertex_runnable(vertex_id, is_active)
|
||||||
|
|
||||||
def build_run_map(self):
|
def build_run_map(self):
|
||||||
"""
|
"""Builds the run map for the graph.
|
||||||
Builds the run map for the graph.
|
|
||||||
|
|
||||||
This method is responsible for building the run map for the graph,
|
This method is responsible for building the run map for the graph,
|
||||||
which maps each node in the graph to its corresponding run function.
|
which maps each node in the graph to its corresponding run function.
|
||||||
|
|
@ -2031,8 +2016,8 @@ class Graph:
|
||||||
self.run_manager.build_run_map(predecessor_map=self.predecessor_map, vertices_to_run=self.vertices_to_run)
|
self.run_manager.build_run_map(predecessor_map=self.predecessor_map, vertices_to_run=self.vertices_to_run)
|
||||||
|
|
||||||
def find_runnable_predecessors_for_successors(self, vertex_id: str) -> list[str]:
|
def find_runnable_predecessors_for_successors(self, vertex_id: str) -> list[str]:
|
||||||
"""
|
"""For each successor of the current vertex, find runnable predecessors if any.
|
||||||
For each successor of the current vertex, find runnable predecessors if any.
|
|
||||||
This checks the direct predecessors of each successor to identify any that are
|
This checks the direct predecessors of each successor to identify any that are
|
||||||
immediately runnable, expanding the search to ensure progress can be made.
|
immediately runnable, expanding the search to ensure progress can be made.
|
||||||
"""
|
"""
|
||||||
|
|
@ -2069,8 +2054,7 @@ class Graph:
|
||||||
self.run_manager.remove_vertex_from_runnables(vertex_id)
|
self.run_manager.remove_vertex_from_runnables(vertex_id)
|
||||||
|
|
||||||
def get_top_level_vertices(self, vertices_ids):
|
def get_top_level_vertices(self, vertices_ids):
|
||||||
"""
|
"""Retrieves the top-level vertices from the given graph based on the provided vertex IDs.
|
||||||
Retrieves the top-level vertices from the given graph based on the provided vertex IDs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vertices_ids (list): A list of vertex IDs.
|
vertices_ids (list): A list of vertex IDs.
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,7 @@ def camel_to_snake(camel_str: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def create_state_model_from_graph(graph: BaseModel) -> type[BaseModel]:
|
def create_state_model_from_graph(graph: BaseModel) -> type[BaseModel]:
|
||||||
"""
|
"""Create a Pydantic state model from a graph representation.
|
||||||
Create a Pydantic state model from a graph representation.
|
|
||||||
|
|
||||||
This function generates a Pydantic model that represents the state of an entire graph.
|
This function generates a Pydantic model that represents the state of an entire graph.
|
||||||
It creates getter methods for each vertex in the graph, allowing access to the state
|
It creates getter methods for each vertex in the graph, allowing access to the state
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ PRIORITY_LIST_OF_INPUTS = ["webhook", "chat"]
|
||||||
|
|
||||||
|
|
||||||
def find_start_component_id(vertices):
|
def find_start_component_id(vertices):
|
||||||
"""
|
"""Finds the component ID from a list of vertices based on a priority list of input types.
|
||||||
Finds the component ID from a list of vertices based on a priority list of input types.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vertices (list): A list of vertex IDs.
|
vertices (list): A list of vertex IDs.
|
||||||
|
|
@ -24,24 +23,18 @@ def find_start_component_id(vertices):
|
||||||
|
|
||||||
|
|
||||||
def find_last_node(nodes, edges):
|
def find_last_node(nodes, edges):
|
||||||
"""
|
"""This function receives a flow and returns the last node."""
|
||||||
This function receives a flow and returns the last node.
|
|
||||||
"""
|
|
||||||
return next((n for n in nodes if all(e["source"] != n["id"] for e in edges)), None)
|
return next((n for n in nodes if all(e["source"] != n["id"] for e in edges)), None)
|
||||||
|
|
||||||
|
|
||||||
def add_parent_node_id(nodes, parent_node_id):
|
def add_parent_node_id(nodes, parent_node_id):
|
||||||
"""
|
"""This function receives a list of nodes and adds a parent_node_id to each node."""
|
||||||
This function receives a list of nodes and adds a parent_node_id to each node.
|
|
||||||
"""
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node["parent_node_id"] = parent_node_id
|
node["parent_node_id"] = parent_node_id
|
||||||
|
|
||||||
|
|
||||||
def add_frozen(nodes, frozen):
|
def add_frozen(nodes, frozen):
|
||||||
"""
|
"""This function receives a list of nodes and adds a frozen to each node."""
|
||||||
This function receives a list of nodes and adds a frozen to each node.
|
|
||||||
"""
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node["data"]["node"]["frozen"] = frozen
|
node["data"]["node"]["frozen"] = frozen
|
||||||
|
|
||||||
|
|
@ -108,8 +101,7 @@ def process_flow(flow_object):
|
||||||
|
|
||||||
|
|
||||||
def update_template(template, g_nodes):
|
def update_template(template, g_nodes):
|
||||||
"""
|
"""Updates the template of a node in a graph with the given template.
|
||||||
Updates the template of a node in a graph with the given template.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
template (dict): The new template to update the node with.
|
template (dict): The new template to update the node with.
|
||||||
|
|
@ -140,8 +132,7 @@ def update_template(template, g_nodes):
|
||||||
|
|
||||||
|
|
||||||
def update_target_handle(new_edge, g_nodes, group_node_id):
|
def update_target_handle(new_edge, g_nodes, group_node_id):
|
||||||
"""
|
"""Updates the target handle of a given edge if it is a proxy node.
|
||||||
Updates the target handle of a given edge if it is a proxy node.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
new_edge (dict): The edge to update.
|
new_edge (dict): The edge to update.
|
||||||
|
|
@ -160,8 +151,7 @@ def update_target_handle(new_edge, g_nodes, group_node_id):
|
||||||
|
|
||||||
|
|
||||||
def set_new_target_handle(proxy_id, new_edge, target_handle, node):
|
def set_new_target_handle(proxy_id, new_edge, target_handle, node):
|
||||||
"""
|
"""Sets a new target handle for a given edge.
|
||||||
Sets a new target handle for a given edge.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
proxy_id (str): The ID of the proxy.
|
proxy_id (str): The ID of the proxy.
|
||||||
|
|
@ -195,12 +185,12 @@ def set_new_target_handle(proxy_id, new_edge, target_handle, node):
|
||||||
|
|
||||||
|
|
||||||
def update_source_handle(new_edge, g_nodes, g_edges):
|
def update_source_handle(new_edge, g_nodes, g_edges):
|
||||||
"""
|
"""Updates the source handle of a given edge to the last node in the flow data.
|
||||||
Updates the source handle of a given edge to the last node in the flow data.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
new_edge (dict): The edge to update.
|
new_edge (dict): The edge to update.
|
||||||
flow_data (dict): The flow data containing the nodes and edges.
|
g_nodes: The graph nodes.
|
||||||
|
g_edges: The graph edges.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The updated edge with the new source handle.
|
dict: The updated edge with the new source handle.
|
||||||
|
|
@ -214,13 +204,15 @@ def update_source_handle(new_edge, g_nodes, g_edges):
|
||||||
|
|
||||||
|
|
||||||
def get_updated_edges(base_flow, g_nodes, g_edges, group_node_id):
|
def get_updated_edges(base_flow, g_nodes, g_edges, group_node_id):
|
||||||
"""
|
"""Get updated edges.
|
||||||
|
|
||||||
Given a base flow, a list of graph nodes and a group node id, returns a list of updated edges.
|
Given a base flow, a list of graph nodes and a group node id, returns a list of updated edges.
|
||||||
An updated edge is an edge that has its target or source handle updated based on the group node id.
|
An updated edge is an edge that has its target or source handle updated based on the group node id.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
base_flow (dict): The base flow containing a list of edges.
|
base_flow (dict): The base flow containing a list of edges.
|
||||||
g_nodes (list): A list of graph nodes.
|
g_nodes (list): A list of graph nodes.
|
||||||
|
g_edges (list): A list of graph edges.
|
||||||
group_node_id (str): The id of the group node.
|
group_node_id (str): The id of the group node.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -323,8 +315,7 @@ def sort_up_to_vertex(
|
||||||
|
|
||||||
|
|
||||||
def has_cycle(vertex_ids: list[str], edges: list[tuple[str, str]]) -> bool:
|
def has_cycle(vertex_ids: list[str], edges: list[tuple[str, str]]) -> bool:
|
||||||
"""
|
"""Determines whether a directed graph represented by a list of vertices and edges contains a cycle.
|
||||||
Determines whether a directed graph represented by a list of vertices and edges contains a cycle.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
vertex_ids (list[str]): A list of vertex IDs.
|
vertex_ids (list[str]): A list of vertex IDs.
|
||||||
|
|
@ -360,8 +351,7 @@ def has_cycle(vertex_ids: list[str], edges: list[tuple[str, str]]) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def find_cycle_edge(entry_point: str, edges: list[tuple[str, str]]) -> tuple[str, str]:
|
def find_cycle_edge(entry_point: str, edges: list[tuple[str, str]]) -> tuple[str, str]:
|
||||||
"""
|
"""Find the edge that causes a cycle in a directed graph starting from a given entry point.
|
||||||
Find the edge that causes a cycle in a directed graph starting from a given entry point.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
entry_point (str): The vertex ID from which to start the search.
|
entry_point (str): The vertex ID from which to start the search.
|
||||||
|
|
@ -398,8 +388,7 @@ def find_cycle_edge(entry_point: str, edges: list[tuple[str, str]]) -> tuple[str
|
||||||
|
|
||||||
|
|
||||||
def find_all_cycle_edges(entry_point: str, edges: list[tuple[str, str]]) -> list[tuple[str, str]]:
|
def find_all_cycle_edges(entry_point: str, edges: list[tuple[str, str]]) -> list[tuple[str, str]]:
|
||||||
"""
|
"""Find all edges that cause cycles in a directed graph starting from a given entry point.
|
||||||
Find all edges that cause cycles in a directed graph starting from a given entry point.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
entry_point (str): The vertex ID from which to start the search.
|
entry_point (str): The vertex ID from which to start the search.
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ from pydantic.fields import FieldInfo
|
||||||
|
|
||||||
|
|
||||||
def __validate_method(method: Callable) -> None:
|
def __validate_method(method: Callable) -> None:
|
||||||
"""
|
"""Validates a method by checking if it has the required attributes.
|
||||||
Validates a method by checking if it has the required attributes.
|
|
||||||
|
|
||||||
This function ensures that the given method belongs to a class with the necessary
|
This function ensures that the given method belongs to a class with the necessary
|
||||||
structure for output handling. It checks for the presence of a __self__ attribute
|
structure for output handling. It checks for the presence of a __self__ attribute
|
||||||
|
|
@ -38,8 +37,7 @@ def __validate_method(method: Callable) -> None:
|
||||||
|
|
||||||
|
|
||||||
def build_output_getter(method: Callable, validate: bool = True) -> Callable:
|
def build_output_getter(method: Callable, validate: bool = True) -> Callable:
|
||||||
"""
|
"""Builds an output getter function for a given method in a graph component.
|
||||||
Builds an output getter function for a given method in a graph component.
|
|
||||||
|
|
||||||
This function creates a new callable that, when invoked, retrieves the output
|
This function creates a new callable that, when invoked, retrieves the output
|
||||||
of the specified method using the get_output_by_method of the method's class.
|
of the specified method using the get_output_by_method of the method's class.
|
||||||
|
|
@ -91,8 +89,7 @@ def build_output_getter(method: Callable, validate: bool = True) -> Callable:
|
||||||
|
|
||||||
|
|
||||||
def build_output_setter(method: Callable, validate: bool = True) -> Callable:
|
def build_output_setter(method: Callable, validate: bool = True) -> Callable:
|
||||||
"""
|
"""Build an output setter function for a given method in a graph component.
|
||||||
Build an output setter function for a given method in a graph component.
|
|
||||||
|
|
||||||
This function creates a new callable that, when invoked, sets the output
|
This function creates a new callable that, when invoked, sets the output
|
||||||
of the specified method using the get_output_by_method of the method's class.
|
of the specified method using the get_output_by_method of the method's class.
|
||||||
|
|
@ -140,8 +137,7 @@ def build_output_setter(method: Callable, validate: bool = True) -> Callable:
|
||||||
|
|
||||||
|
|
||||||
def create_state_model(model_name: str = "State", validate: bool = True, **kwargs) -> type:
|
def create_state_model(model_name: str = "State", validate: bool = True, **kwargs) -> type:
|
||||||
"""
|
"""Create a dynamic Pydantic state model based on the provided keyword arguments.
|
||||||
Create a dynamic Pydantic state model based on the provided keyword arguments.
|
|
||||||
|
|
||||||
This function generates a Pydantic model class with fields corresponding to the
|
This function generates a Pydantic model class with fields corresponding to the
|
||||||
provided keyword arguments. It can handle various types of field definitions,
|
provided keyword arguments. It can handle various types of field definitions,
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,11 @@ def flatten_list(list_of_lists: list[list | Any]) -> list:
|
||||||
|
|
||||||
|
|
||||||
def serialize_field(value):
|
def serialize_field(value):
|
||||||
"""Unified serialization function for handling both BaseModel and Document types,
|
"""Serialize field.
|
||||||
including handling lists of these types."""
|
|
||||||
|
|
||||||
|
Unified serialization function for handling both BaseModel and Document types,
|
||||||
|
including handling lists of these types.
|
||||||
|
"""
|
||||||
if isinstance(value, list | tuple):
|
if isinstance(value, list | tuple):
|
||||||
return [serialize_field(v) for v in value]
|
return [serialize_field(v) for v in value]
|
||||||
if isinstance(value, Document):
|
if isinstance(value, Document):
|
||||||
|
|
@ -121,9 +123,7 @@ def post_process_raw(raw, artifact_type: str):
|
||||||
|
|
||||||
|
|
||||||
def _vertex_to_primitive_dict(target: Vertex) -> dict:
|
def _vertex_to_primitive_dict(target: Vertex) -> dict:
|
||||||
"""
|
"""Cleans the parameters of the target vertex."""
|
||||||
Cleans the parameters of the target vertex.
|
|
||||||
"""
|
|
||||||
# Removes all keys that the values aren't python types like str, int, bool, etc.
|
# Removes all keys that the values aren't python types like str, int, bool, etc.
|
||||||
params = {
|
params = {
|
||||||
key: value for key, value in target.params.items() if isinstance(value, str | int | bool | float | list | dict)
|
key: value for key, value in target.params.items() if isinstance(value, str | int | bool | float | list | dict)
|
||||||
|
|
|
||||||
|
|
@ -438,11 +438,12 @@ class Vertex:
|
||||||
self._raw_params = params.copy()
|
self._raw_params = params.copy()
|
||||||
|
|
||||||
def update_raw_params(self, new_params: Mapping[str, str | list[str]], overwrite: bool = False):
|
def update_raw_params(self, new_params: Mapping[str, str | list[str]], overwrite: bool = False):
|
||||||
"""
|
"""Update the raw parameters of the vertex with the given new parameters.
|
||||||
Update the raw parameters of the vertex with the given new parameters.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
new_params (Dict[str, Any]): The new parameters to update.
|
new_params (Dict[str, Any]): The new parameters to update.
|
||||||
|
overwrite (bool, optional): Whether to overwrite the existing parameters.
|
||||||
|
Defaults to False.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If any key in new_params is not found in self._raw_params.
|
ValueError: If any key in new_params is not found in self._raw_params.
|
||||||
|
|
@ -461,9 +462,7 @@ class Vertex:
|
||||||
self.updated_raw_params = True
|
self.updated_raw_params = True
|
||||||
|
|
||||||
def has_cycle_edges(self):
|
def has_cycle_edges(self):
|
||||||
"""
|
"""Checks if the vertex has any cycle edges."""
|
||||||
Checks if the vertex has any cycle edges.
|
|
||||||
"""
|
|
||||||
return self._has_cycle_edges
|
return self._has_cycle_edges
|
||||||
|
|
||||||
async def instantiate_component(self, user_id=None):
|
async def instantiate_component(self, user_id=None):
|
||||||
|
|
@ -479,9 +478,7 @@ class Vertex:
|
||||||
user_id=None,
|
user_id=None,
|
||||||
event_manager: EventManager | None = None,
|
event_manager: EventManager | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""Initiate the build process."""
|
||||||
Initiate the build process.
|
|
||||||
"""
|
|
||||||
logger.debug(f"Building {self.display_name}")
|
logger.debug(f"Building {self.display_name}")
|
||||||
await self._build_each_vertex_in_params_dict(user_id)
|
await self._build_each_vertex_in_params_dict(user_id)
|
||||||
|
|
||||||
|
|
@ -509,8 +506,7 @@ class Vertex:
|
||||||
self._built = True
|
self._built = True
|
||||||
|
|
||||||
def extract_messages_from_artifacts(self, artifacts: dict[str, Any]) -> list[dict]:
|
def extract_messages_from_artifacts(self, artifacts: dict[str, Any]) -> list[dict]:
|
||||||
"""
|
"""Extracts messages from the artifacts.
|
||||||
Extracts messages from the artifacts.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
artifacts (Dict[str, Any]): The artifacts to extract messages from.
|
artifacts (Dict[str, Any]): The artifacts to extract messages from.
|
||||||
|
|
@ -567,9 +563,7 @@ class Vertex:
|
||||||
self.set_result(result_dict)
|
self.set_result(result_dict)
|
||||||
|
|
||||||
async def _build_each_vertex_in_params_dict(self, user_id=None):
|
async def _build_each_vertex_in_params_dict(self, user_id=None):
|
||||||
"""
|
"""Iterates over each vertex in the params dictionary and builds it."""
|
||||||
Iterates over each vertex in the params dictionary and builds it.
|
|
||||||
"""
|
|
||||||
for key, value in self._raw_params.items():
|
for key, value in self._raw_params.items():
|
||||||
if self._is_vertex(value):
|
if self._is_vertex(value):
|
||||||
if value == self:
|
if value == self:
|
||||||
|
|
@ -594,9 +588,7 @@ class Vertex:
|
||||||
key,
|
key,
|
||||||
vertices_dict: dict[str, Vertex],
|
vertices_dict: dict[str, Vertex],
|
||||||
):
|
):
|
||||||
"""
|
"""Iterates over a dictionary of vertices, builds each and updates the params dictionary."""
|
||||||
Iterates over a dictionary of vertices, builds each and updates the params dictionary.
|
|
||||||
"""
|
|
||||||
for sub_key, value in vertices_dict.items():
|
for sub_key, value in vertices_dict.items():
|
||||||
if not self._is_vertex(value):
|
if not self._is_vertex(value):
|
||||||
self.params[key][sub_key] = value
|
self.params[key][sub_key] = value
|
||||||
|
|
@ -605,20 +597,15 @@ class Vertex:
|
||||||
self.params[key][sub_key] = result
|
self.params[key][sub_key] = result
|
||||||
|
|
||||||
def _is_vertex(self, value):
|
def _is_vertex(self, value):
|
||||||
"""
|
"""Checks if the provided value is an instance of Vertex."""
|
||||||
Checks if the provided value is an instance of Vertex.
|
|
||||||
"""
|
|
||||||
return isinstance(value, Vertex)
|
return isinstance(value, Vertex)
|
||||||
|
|
||||||
def _is_list_of_vertices(self, value):
|
def _is_list_of_vertices(self, value):
|
||||||
"""
|
"""Checks if the provided value is a list of Vertex instances."""
|
||||||
Checks if the provided value is a list of Vertex instances.
|
|
||||||
"""
|
|
||||||
return all(self._is_vertex(vertex) for vertex in value)
|
return all(self._is_vertex(vertex) for vertex in value)
|
||||||
|
|
||||||
async def get_result(self, requester: Vertex, target_handle_name: str | None = None) -> Any:
|
async def get_result(self, requester: Vertex, target_handle_name: str | None = None) -> Any:
|
||||||
"""
|
"""Retrieves the result of the vertex.
|
||||||
Retrieves the result of the vertex.
|
|
||||||
|
|
||||||
This is a read-only method so it raises an error if the vertex has not been built yet.
|
This is a read-only method so it raises an error if the vertex has not been built yet.
|
||||||
|
|
||||||
|
|
@ -636,8 +623,7 @@ class Vertex:
|
||||||
task.add_done_callback(self.log_transaction_tasks.discard)
|
task.add_done_callback(self.log_transaction_tasks.discard)
|
||||||
|
|
||||||
async def _get_result(self, requester: Vertex, target_handle_name: str | None = None) -> Any:
|
async def _get_result(self, requester: Vertex, target_handle_name: str | None = None) -> Any:
|
||||||
"""
|
"""Retrieves the result of the built component.
|
||||||
Retrieves the result of the built component.
|
|
||||||
|
|
||||||
If the component has not been built yet, a ValueError is raised.
|
If the component has not been built yet, a ValueError is raised.
|
||||||
|
|
||||||
|
|
@ -657,10 +643,7 @@ class Vertex:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
async def _build_vertex_and_update_params(self, key, vertex: Vertex):
|
async def _build_vertex_and_update_params(self, key, vertex: Vertex):
|
||||||
"""
|
"""Builds a given vertex and updates the params dictionary accordingly."""
|
||||||
Builds a given vertex and updates the params dictionary accordingly.
|
|
||||||
"""
|
|
||||||
|
|
||||||
result = await vertex.get_result(self, target_handle_name=key)
|
result = await vertex.get_result(self, target_handle_name=key)
|
||||||
self._handle_func(key, result)
|
self._handle_func(key, result)
|
||||||
if isinstance(result, list):
|
if isinstance(result, list):
|
||||||
|
|
@ -672,9 +655,7 @@ class Vertex:
|
||||||
key,
|
key,
|
||||||
vertices: list[Vertex],
|
vertices: list[Vertex],
|
||||||
):
|
):
|
||||||
"""
|
"""Iterates over a list of vertices, builds each and updates the params dictionary."""
|
||||||
Iterates over a list of vertices, builds each and updates the params dictionary.
|
|
||||||
"""
|
|
||||||
self.params[key] = []
|
self.params[key] = []
|
||||||
for vertex in vertices:
|
for vertex in vertices:
|
||||||
result = await vertex.get_result(self, target_handle_name=key)
|
result = await vertex.get_result(self, target_handle_name=key)
|
||||||
|
|
@ -700,9 +681,7 @@ class Vertex:
|
||||||
raise ValueError(msg) from e
|
raise ValueError(msg) from e
|
||||||
|
|
||||||
def _handle_func(self, key, result):
|
def _handle_func(self, key, result):
|
||||||
"""
|
"""Handles 'func' key by checking if the result is a function and setting it as coroutine."""
|
||||||
Handles 'func' key by checking if the result is a function and setting it as coroutine.
|
|
||||||
"""
|
|
||||||
if key == "func":
|
if key == "func":
|
||||||
if not isinstance(result, types.FunctionType):
|
if not isinstance(result, types.FunctionType):
|
||||||
if hasattr(result, "run"):
|
if hasattr(result, "run"):
|
||||||
|
|
@ -715,9 +694,7 @@ class Vertex:
|
||||||
self.params["coroutine"] = sync_to_async(result)
|
self.params["coroutine"] = sync_to_async(result)
|
||||||
|
|
||||||
def _extend_params_list_with_result(self, key, result):
|
def _extend_params_list_with_result(self, key, result):
|
||||||
"""
|
"""Extends a list in the params dictionary with the given result if it exists."""
|
||||||
Extends a list in the params dictionary with the given result if it exists.
|
|
||||||
"""
|
|
||||||
if isinstance(self.params[key], list):
|
if isinstance(self.params[key], list):
|
||||||
self.params[key].extend(result)
|
self.params[key].extend(result)
|
||||||
|
|
||||||
|
|
@ -741,9 +718,7 @@ class Vertex:
|
||||||
raise ComponentBuildException(msg, tb) from exc
|
raise ComponentBuildException(msg, tb) from exc
|
||||||
|
|
||||||
def _update_built_object_and_artifacts(self, result: Any | tuple[Any, dict] | tuple[Component, Any, dict]):
|
def _update_built_object_and_artifacts(self, result: Any | tuple[Any, dict] | tuple[Component, Any, dict]):
|
||||||
"""
|
"""Updates the built object and its artifacts."""
|
||||||
Updates the built object and its artifacts.
|
|
||||||
"""
|
|
||||||
if isinstance(result, tuple):
|
if isinstance(result, tuple):
|
||||||
if len(result) == 2: # noqa: PLR2004
|
if len(result) == 2: # noqa: PLR2004
|
||||||
self._built_object, self.artifacts = result
|
self._built_object, self.artifacts = result
|
||||||
|
|
@ -759,9 +734,7 @@ class Vertex:
|
||||||
self._built_object = result
|
self._built_object = result
|
||||||
|
|
||||||
def _validate_built_object(self):
|
def _validate_built_object(self):
|
||||||
"""
|
"""Checks if the built object is None and raises a ValueError if so."""
|
||||||
Checks if the built object is None and raises a ValueError if so.
|
|
||||||
"""
|
|
||||||
if isinstance(self._built_object, UnbuiltObject):
|
if isinstance(self._built_object, UnbuiltObject):
|
||||||
msg = f"{self.display_name}: {self._built_object_repr()}"
|
msg = f"{self.display_name}: {self._built_object_repr()}"
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,7 @@ class ComponentVertex(Vertex):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _update_built_object_and_artifacts(self, result):
|
def _update_built_object_and_artifacts(self, result):
|
||||||
"""
|
"""Updates the built object and its artifacts."""
|
||||||
Updates the built object and its artifacts.
|
|
||||||
"""
|
|
||||||
if isinstance(result, tuple):
|
if isinstance(result, tuple):
|
||||||
if len(result) == 2: # noqa: PLR2004
|
if len(result) == 2: # noqa: PLR2004
|
||||||
self._built_object, self.artifacts = result
|
self._built_object, self.artifacts = result
|
||||||
|
|
@ -77,8 +75,7 @@ class ComponentVertex(Vertex):
|
||||||
self.add_result(key, value)
|
self.add_result(key, value)
|
||||||
|
|
||||||
def get_edge_with_target(self, target_id: str) -> Generator[CycleEdge, None, None]:
|
def get_edge_with_target(self, target_id: str) -> Generator[CycleEdge, None, None]:
|
||||||
"""
|
"""Get the edge with the target id.
|
||||||
Get the edge with the target id.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
target_id: The target id of the edge.
|
target_id: The target id of the edge.
|
||||||
|
|
@ -91,8 +88,7 @@ class ComponentVertex(Vertex):
|
||||||
yield edge
|
yield edge
|
||||||
|
|
||||||
async def _get_result(self, requester: Vertex, target_handle_name: str | None = None) -> Any:
|
async def _get_result(self, requester: Vertex, target_handle_name: str | None = None) -> Any:
|
||||||
"""
|
"""Retrieves the result of the built component.
|
||||||
Retrieves the result of the built component.
|
|
||||||
|
|
||||||
If the component has not been built yet, a ValueError is raised.
|
If the component has not been built yet, a ValueError is raised.
|
||||||
|
|
||||||
|
|
@ -151,8 +147,7 @@ class ComponentVertex(Vertex):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def extract_messages_from_artifacts(self, artifacts: dict[str, Any]) -> list[dict]:
|
def extract_messages_from_artifacts(self, artifacts: dict[str, Any]) -> list[dict]:
|
||||||
"""
|
"""Extracts messages from the artifacts.
|
||||||
Extracts messages from the artifacts.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
artifacts (Dict[str, Any]): The artifacts to extract messages from.
|
artifacts (Dict[str, Any]): The artifacts to extract messages from.
|
||||||
|
|
@ -236,8 +231,7 @@ class InterfaceVertex(ComponentVertex):
|
||||||
return super()._built_object_repr()
|
return super()._built_object_repr()
|
||||||
|
|
||||||
def _process_chat_component(self):
|
def _process_chat_component(self):
|
||||||
"""
|
"""Process the chat component and return the message.
|
||||||
Process the chat component and return the message.
|
|
||||||
|
|
||||||
This method processes the chat component by extracting the necessary parameters
|
This method processes the chat component by extracting the necessary parameters
|
||||||
such as sender, sender_name, and message from the `params` dictionary. It then
|
such as sender, sender_name, and message from the `params` dictionary. It then
|
||||||
|
|
@ -324,8 +318,7 @@ class InterfaceVertex(ComponentVertex):
|
||||||
return message
|
return message
|
||||||
|
|
||||||
def _process_data_component(self):
|
def _process_data_component(self):
|
||||||
"""
|
"""Process the record component of the vertex.
|
||||||
Process the record component of the vertex.
|
|
||||||
|
|
||||||
If the built object is an instance of `Data`, it calls the `model_dump` method
|
If the built object is an instance of `Data`, it calls the `model_dump` method
|
||||||
and assigns the result to the `artifacts` attribute.
|
and assigns the result to the `artifacts` attribute.
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
def build_clean_params(target: Vertex) -> dict:
|
def build_clean_params(target: Vertex) -> dict:
|
||||||
"""
|
"""Cleans the parameters of the target vertex."""
|
||||||
Cleans the parameters of the target vertex.
|
|
||||||
"""
|
|
||||||
# Removes all keys that the values aren't python types like str, int, bool, etc.
|
# Removes all keys that the values aren't python types like str, int, bool, etc.
|
||||||
params = {
|
params = {
|
||||||
key: value for key, value in target.params.items() if isinstance(value, str | int | bool | float | list | dict)
|
key: value for key, value in target.params.items() if isinstance(value, str | int | bool | float | list | dict)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ from langflow.schema.message import Message
|
||||||
|
|
||||||
|
|
||||||
def docs_to_data(documents: list[Document]) -> list[Data]:
|
def docs_to_data(documents: list[Document]) -> list[Data]:
|
||||||
"""
|
"""Converts a list of Documents to a list of Data.
|
||||||
Converts a list of Documents to a list of Data.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
documents (list[Document]): The list of Documents to convert.
|
documents (list[Document]): The list of Documents to convert.
|
||||||
|
|
@ -18,11 +17,12 @@ def docs_to_data(documents: list[Document]) -> list[Data]:
|
||||||
|
|
||||||
|
|
||||||
def data_to_text(template: str, data: Data | list[Data], sep: str = "\n") -> str:
|
def data_to_text(template: str, data: Data | list[Data], sep: str = "\n") -> str:
|
||||||
"""
|
"""Converts a list of Data to a list of texts.
|
||||||
Converts a list of Data to a list of texts.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
template (str): The template to use for the conversion.
|
||||||
data (list[Data]): The list of Data to convert.
|
data (list[Data]): The list of Data to convert.
|
||||||
|
sep (str): The separator used to join the data.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list[str]: The converted list of texts.
|
list[str]: The converted list of texts.
|
||||||
|
|
@ -41,10 +41,10 @@ def data_to_text(template: str, data: Data | list[Data], sep: str = "\n") -> str
|
||||||
|
|
||||||
|
|
||||||
def messages_to_text(template: str, messages: Message | list[Message]) -> str:
|
def messages_to_text(template: str, messages: Message | list[Message]) -> str:
|
||||||
"""
|
"""Converts a list of Messages to a list of texts.
|
||||||
Converts a list of Messages to a list of texts.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
template (str): The template to use for the conversion.
|
||||||
messages (list[Message]): The list of Messages to convert.
|
messages (list[Message]): The list of Messages to convert.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
|
||||||
|
|
@ -125,12 +125,12 @@ async def run_flow(
|
||||||
def generate_function_for_flow(
|
def generate_function_for_flow(
|
||||||
inputs: list[Vertex], flow_id: str, user_id: str | UUID | None
|
inputs: list[Vertex], flow_id: str, user_id: str | UUID | None
|
||||||
) -> Callable[..., Awaitable[Any]]:
|
) -> Callable[..., Awaitable[Any]]:
|
||||||
"""
|
"""Generate a dynamic flow function based on the given inputs and flow ID.
|
||||||
Generate a dynamic flow function based on the given inputs and flow ID.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
inputs (List[Vertex]): The list of input vertices for the flow.
|
inputs (List[Vertex]): The list of input vertices for the flow.
|
||||||
flow_id (str): The ID of the flow.
|
flow_id (str): The ID of the flow.
|
||||||
|
user_id (str | UUID | None): The user ID associated with the flow.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Coroutine: The dynamic flow function.
|
Coroutine: The dynamic flow function.
|
||||||
|
|
@ -201,12 +201,12 @@ async def flow_function({func_args}):
|
||||||
def build_function_and_schema(
|
def build_function_and_schema(
|
||||||
flow_data: Data, graph: Graph, user_id: str | UUID | None
|
flow_data: Data, graph: Graph, user_id: str | UUID | None
|
||||||
) -> tuple[Callable[..., Awaitable[Any]], type[BaseModel]]:
|
) -> tuple[Callable[..., Awaitable[Any]], type[BaseModel]]:
|
||||||
"""
|
"""Builds a dynamic function and schema for a given flow.
|
||||||
Builds a dynamic function and schema for a given flow.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
flow_data (Data): The flow record containing information about the flow.
|
flow_data (Data): The flow record containing information about the flow.
|
||||||
graph (Graph): The graph representing the flow.
|
graph (Graph): The graph representing the flow.
|
||||||
|
user_id (str): The user ID associated with the flow.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[Callable, BaseModel]: A tuple containing the dynamic function and the schema.
|
Tuple[Callable, BaseModel]: A tuple containing the dynamic function and the schema.
|
||||||
|
|
@ -219,8 +219,7 @@ def build_function_and_schema(
|
||||||
|
|
||||||
|
|
||||||
def get_flow_inputs(graph: Graph) -> list[Vertex]:
|
def get_flow_inputs(graph: Graph) -> list[Vertex]:
|
||||||
"""
|
"""Retrieves the flow inputs from the given graph.
|
||||||
Retrieves the flow inputs from the given graph.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
graph (Graph): The graph object representing the flow.
|
graph (Graph): The graph object representing the flow.
|
||||||
|
|
@ -232,8 +231,7 @@ def get_flow_inputs(graph: Graph) -> list[Vertex]:
|
||||||
|
|
||||||
|
|
||||||
def build_schema_from_inputs(name: str, inputs: list[Vertex]) -> type[BaseModel]:
|
def build_schema_from_inputs(name: str, inputs: list[Vertex]) -> type[BaseModel]:
|
||||||
"""
|
"""Builds a schema from the given inputs.
|
||||||
Builds a schema from the given inputs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The name of the schema.
|
name (str): The name of the schema.
|
||||||
|
|
@ -253,8 +251,7 @@ def build_schema_from_inputs(name: str, inputs: list[Vertex]) -> type[BaseModel]
|
||||||
|
|
||||||
|
|
||||||
def get_arg_names(inputs: list[Vertex]) -> list[dict[str, str]]:
|
def get_arg_names(inputs: list[Vertex]) -> list[dict[str, str]]:
|
||||||
"""
|
"""Returns a list of dictionaries containing the component name and its corresponding argument name.
|
||||||
Returns a list of dictionaries containing the component name and its corresponding argument name.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
inputs (List[Vertex]): A list of Vertex objects representing the inputs.
|
inputs (List[Vertex]): A list of Vertex objects representing the inputs.
|
||||||
|
|
|
||||||
|
|
@ -518,8 +518,7 @@ def _is_valid_uuid(val):
|
||||||
|
|
||||||
|
|
||||||
def load_flows_from_directory():
|
def load_flows_from_directory():
|
||||||
"""
|
"""On langflow startup, this loads all flows from the directory specified in the settings.
|
||||||
On langflow startup, this loads all flows from the directory specified in the settings.
|
|
||||||
|
|
||||||
All flows are uploaded into the default folder for the superuser.
|
All flows are uploaded into the default folder for the superuser.
|
||||||
Note that this feature currently only works if AUTO_LOGIN is enabled in the settings.
|
Note that this feature currently only works if AUTO_LOGIN is enabled in the settings.
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,7 @@ class TableInput(BaseInputMixin, MetadataTraceMixin, TableMixin, ListableInputMi
|
||||||
|
|
||||||
|
|
||||||
class HandleInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin):
|
class HandleInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin):
|
||||||
"""
|
"""Represents an Input that has a Handle to a specific type (e.g. BaseLanguageModel, BaseRetriever, etc.).
|
||||||
Represents an Input that has a Handle to a specific type (e.g. BaseLanguageModel, BaseRetriever, etc.)
|
|
||||||
|
|
||||||
This class inherits from the `BaseInputMixin` and `ListableInputMixin` classes.
|
This class inherits from the `BaseInputMixin` and `ListableInputMixin` classes.
|
||||||
|
|
||||||
|
|
@ -64,8 +63,7 @@ class HandleInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin):
|
||||||
|
|
||||||
|
|
||||||
class DataInput(HandleInput, InputTraceMixin, ListableInputMixin):
|
class DataInput(HandleInput, InputTraceMixin, ListableInputMixin):
|
||||||
"""
|
"""Represents an Input that has a Handle that receives a Data object.
|
||||||
Represents an Input that has a Handle that receives a Data object.
|
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
input_types (list[str]): A list of input types supported by this data input.
|
input_types (list[str]): A list of input types supported by this data input.
|
||||||
|
|
@ -90,8 +88,7 @@ class StrInput(BaseInputMixin, ListableInputMixin, DatabaseLoadMixin, MetadataTr
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _validate_value(v: Any, _info):
|
def _validate_value(v: Any, _info):
|
||||||
"""
|
"""Validates the given value and returns the processed value.
|
||||||
Validates the given value and returns the processed value.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
v (Any): The value to be validated.
|
v (Any): The value to be validated.
|
||||||
|
|
@ -121,8 +118,7 @@ class StrInput(BaseInputMixin, ListableInputMixin, DatabaseLoadMixin, MetadataTr
|
||||||
@field_validator("value")
|
@field_validator("value")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_value(cls, v: Any, _info):
|
def validate_value(cls, v: Any, _info):
|
||||||
"""
|
"""Validates the given value and returns the processed value.
|
||||||
Validates the given value and returns the processed value.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
v (Any): The value to be validated.
|
v (Any): The value to be validated.
|
||||||
|
|
@ -155,8 +151,7 @@ class MessageInput(StrInput, InputTraceMixin):
|
||||||
|
|
||||||
|
|
||||||
class MessageTextInput(StrInput, MetadataTraceMixin, InputTraceMixin):
|
class MessageTextInput(StrInput, MetadataTraceMixin, InputTraceMixin):
|
||||||
"""
|
"""Represents a text input component for the Langflow system.
|
||||||
Represents a text input component for the Langflow system.
|
|
||||||
|
|
||||||
This component is used to handle text inputs in the Langflow system.
|
This component is used to handle text inputs in the Langflow system.
|
||||||
It provides methods for validating and processing text values.
|
It provides methods for validating and processing text values.
|
||||||
|
|
@ -170,8 +165,7 @@ class MessageTextInput(StrInput, MetadataTraceMixin, InputTraceMixin):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _validate_value(v: Any, _info):
|
def _validate_value(v: Any, _info):
|
||||||
"""
|
"""Validates the given value and returns the processed value.
|
||||||
Validates the given value and returns the processed value.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
v (Any): The value to be validated.
|
v (Any): The value to be validated.
|
||||||
|
|
@ -211,8 +205,7 @@ class MessageTextInput(StrInput, MetadataTraceMixin, InputTraceMixin):
|
||||||
|
|
||||||
|
|
||||||
class MultilineInput(MessageTextInput, MultilineMixin, InputTraceMixin):
|
class MultilineInput(MessageTextInput, MultilineMixin, InputTraceMixin):
|
||||||
"""
|
"""Represents a multiline input field.
|
||||||
Represents a multiline input field.
|
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
field_type (SerializableFieldTypes): The type of the field. Defaults to FieldTypes.TEXT.
|
field_type (SerializableFieldTypes): The type of the field. Defaults to FieldTypes.TEXT.
|
||||||
|
|
@ -224,8 +217,7 @@ class MultilineInput(MessageTextInput, MultilineMixin, InputTraceMixin):
|
||||||
|
|
||||||
|
|
||||||
class MultilineSecretInput(MessageTextInput, MultilineMixin, InputTraceMixin):
|
class MultilineSecretInput(MessageTextInput, MultilineMixin, InputTraceMixin):
|
||||||
"""
|
"""Represents a multiline input field.
|
||||||
Represents a multiline input field.
|
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
field_type (SerializableFieldTypes): The type of the field. Defaults to FieldTypes.TEXT.
|
field_type (SerializableFieldTypes): The type of the field. Defaults to FieldTypes.TEXT.
|
||||||
|
|
@ -238,8 +230,7 @@ class MultilineSecretInput(MessageTextInput, MultilineMixin, InputTraceMixin):
|
||||||
|
|
||||||
|
|
||||||
class SecretStrInput(BaseInputMixin, DatabaseLoadMixin):
|
class SecretStrInput(BaseInputMixin, DatabaseLoadMixin):
|
||||||
"""
|
"""Represents a field with password field type.
|
||||||
Represents a field with password field type.
|
|
||||||
|
|
||||||
This class inherits from `BaseInputMixin` and `DatabaseLoadMixin`.
|
This class inherits from `BaseInputMixin` and `DatabaseLoadMixin`.
|
||||||
|
|
||||||
|
|
@ -257,8 +248,7 @@ class SecretStrInput(BaseInputMixin, DatabaseLoadMixin):
|
||||||
@field_validator("value")
|
@field_validator("value")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_value(cls, v: Any, _info):
|
def validate_value(cls, v: Any, _info):
|
||||||
"""
|
"""Validates the given value and returns the processed value.
|
||||||
Validates the given value and returns the processed value.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
v (Any): The value to be validated.
|
v (Any): The value to be validated.
|
||||||
|
|
@ -298,8 +288,7 @@ class SecretStrInput(BaseInputMixin, DatabaseLoadMixin):
|
||||||
|
|
||||||
|
|
||||||
class IntInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMixin):
|
class IntInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMixin):
|
||||||
"""
|
"""Represents an integer field.
|
||||||
Represents an integer field.
|
|
||||||
|
|
||||||
This class represents an integer input and provides functionality for handling integer values.
|
This class represents an integer input and provides functionality for handling integer values.
|
||||||
It inherits from the `BaseInputMixin`, `ListableInputMixin`, and `RangeMixin` classes.
|
It inherits from the `BaseInputMixin`, `ListableInputMixin`, and `RangeMixin` classes.
|
||||||
|
|
@ -313,8 +302,7 @@ class IntInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMixi
|
||||||
@field_validator("value")
|
@field_validator("value")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_value(cls, v: Any, _info):
|
def validate_value(cls, v: Any, _info):
|
||||||
"""
|
"""Validates the given value and returns the processed value.
|
||||||
Validates the given value and returns the processed value.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
v (Any): The value to be validated.
|
v (Any): The value to be validated.
|
||||||
|
|
@ -326,7 +314,6 @@ class IntInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMixi
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If the value is not of a valid type or if the input is missing a required key.
|
ValueError: If the value is not of a valid type or if the input is missing a required key.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if v and not isinstance(v, int | float):
|
if v and not isinstance(v, int | float):
|
||||||
msg = f"Invalid value type {type(v)} for input {_info.data.get('name')}."
|
msg = f"Invalid value type {type(v)} for input {_info.data.get('name')}."
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
@ -336,8 +323,7 @@ class IntInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMixi
|
||||||
|
|
||||||
|
|
||||||
class FloatInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMixin):
|
class FloatInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMixin):
|
||||||
"""
|
"""Represents a float field.
|
||||||
Represents a float field.
|
|
||||||
|
|
||||||
This class represents a float input and provides functionality for handling float values.
|
This class represents a float input and provides functionality for handling float values.
|
||||||
It inherits from the `BaseInputMixin`, `ListableInputMixin`, and `RangeMixin` classes.
|
It inherits from the `BaseInputMixin`, `ListableInputMixin`, and `RangeMixin` classes.
|
||||||
|
|
@ -351,8 +337,7 @@ class FloatInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMi
|
||||||
@field_validator("value")
|
@field_validator("value")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_value(cls, v: Any, _info):
|
def validate_value(cls, v: Any, _info):
|
||||||
"""
|
"""Validates the given value and returns the processed value.
|
||||||
Validates the given value and returns the processed value.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
v (Any): The value to be validated.
|
v (Any): The value to be validated.
|
||||||
|
|
@ -373,8 +358,7 @@ class FloatInput(BaseInputMixin, ListableInputMixin, RangeMixin, MetadataTraceMi
|
||||||
|
|
||||||
|
|
||||||
class BoolInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin):
|
class BoolInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin):
|
||||||
"""
|
"""Represents a boolean field.
|
||||||
Represents a boolean field.
|
|
||||||
|
|
||||||
This class represents a boolean input and provides functionality for handling boolean values.
|
This class represents a boolean input and provides functionality for handling boolean values.
|
||||||
It inherits from the `BaseInputMixin` and `ListableInputMixin` classes.
|
It inherits from the `BaseInputMixin` and `ListableInputMixin` classes.
|
||||||
|
|
@ -389,8 +373,7 @@ class BoolInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin):
|
||||||
|
|
||||||
|
|
||||||
class NestedDictInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin, InputTraceMixin):
|
class NestedDictInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin, InputTraceMixin):
|
||||||
"""
|
"""Represents a nested dictionary field.
|
||||||
Represents a nested dictionary field.
|
|
||||||
|
|
||||||
This class represents a nested dictionary input and provides functionality for handling dictionary values.
|
This class represents a nested dictionary input and provides functionality for handling dictionary values.
|
||||||
It inherits from the `BaseInputMixin` and `ListableInputMixin` classes.
|
It inherits from the `BaseInputMixin` and `ListableInputMixin` classes.
|
||||||
|
|
@ -405,8 +388,7 @@ class NestedDictInput(BaseInputMixin, ListableInputMixin, MetadataTraceMixin, In
|
||||||
|
|
||||||
|
|
||||||
class DictInput(BaseInputMixin, ListableInputMixin, InputTraceMixin):
|
class DictInput(BaseInputMixin, ListableInputMixin, InputTraceMixin):
|
||||||
"""
|
"""Represents a dictionary field.
|
||||||
Represents a dictionary field.
|
|
||||||
|
|
||||||
This class represents a dictionary input and provides functionality for handling dictionary values.
|
This class represents a dictionary input and provides functionality for handling dictionary values.
|
||||||
It inherits from the `BaseInputMixin` and `ListableInputMixin` classes.
|
It inherits from the `BaseInputMixin` and `ListableInputMixin` classes.
|
||||||
|
|
@ -421,8 +403,7 @@ class DictInput(BaseInputMixin, ListableInputMixin, InputTraceMixin):
|
||||||
|
|
||||||
|
|
||||||
class DropdownInput(BaseInputMixin, DropDownMixin, MetadataTraceMixin):
|
class DropdownInput(BaseInputMixin, DropDownMixin, MetadataTraceMixin):
|
||||||
"""
|
"""Represents a dropdown input field.
|
||||||
Represents a dropdown input field.
|
|
||||||
|
|
||||||
This class represents a dropdown input field and provides functionality for handling dropdown values.
|
This class represents a dropdown input field and provides functionality for handling dropdown values.
|
||||||
It inherits from the `BaseInputMixin` and `DropDownMixin` classes.
|
It inherits from the `BaseInputMixin` and `DropDownMixin` classes.
|
||||||
|
|
@ -439,8 +420,7 @@ class DropdownInput(BaseInputMixin, DropDownMixin, MetadataTraceMixin):
|
||||||
|
|
||||||
|
|
||||||
class MultiselectInput(BaseInputMixin, ListableInputMixin, DropDownMixin, MetadataTraceMixin):
|
class MultiselectInput(BaseInputMixin, ListableInputMixin, DropDownMixin, MetadataTraceMixin):
|
||||||
"""
|
"""Represents a multiselect input field.
|
||||||
Represents a multiselect input field.
|
|
||||||
|
|
||||||
This class represents a multiselect input field and provides functionality for handling multiselect values.
|
This class represents a multiselect input field and provides functionality for handling multiselect values.
|
||||||
It inherits from the `BaseInputMixin`, `ListableInputMixin` and `DropDownMixin` classes.
|
It inherits from the `BaseInputMixin`, `ListableInputMixin` and `DropDownMixin` classes.
|
||||||
|
|
@ -471,8 +451,7 @@ class MultiselectInput(BaseInputMixin, ListableInputMixin, DropDownMixin, Metada
|
||||||
|
|
||||||
|
|
||||||
class FileInput(BaseInputMixin, ListableInputMixin, FileMixin, MetadataTraceMixin):
|
class FileInput(BaseInputMixin, ListableInputMixin, FileMixin, MetadataTraceMixin):
|
||||||
"""
|
"""Represents a file field.
|
||||||
Represents a file field.
|
|
||||||
|
|
||||||
This class represents a file input and provides functionality for handling file values.
|
This class represents a file input and provides functionality for handling file values.
|
||||||
It inherits from the `BaseInputMixin`, `ListableInputMixin`, and `FileMixin` classes.
|
It inherits from the `BaseInputMixin`, `ListableInputMixin`, and `FileMixin` classes.
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from typing import Any
|
||||||
|
|
||||||
|
|
||||||
def import_module(module_path: str) -> Any:
|
def import_module(module_path: str) -> Any:
|
||||||
"""Import module from module path"""
|
"""Import module from module path."""
|
||||||
if "from" not in module_path:
|
if "from" not in module_path:
|
||||||
# Import the module using the module path
|
# Import the module using the module path
|
||||||
return importlib.import_module(module_path)
|
return importlib.import_module(module_path)
|
||||||
|
|
@ -19,7 +19,7 @@ def import_module(module_path: str) -> Any:
|
||||||
|
|
||||||
|
|
||||||
def import_class(class_path: str) -> Any:
|
def import_class(class_path: str) -> Any:
|
||||||
"""Import class from class path"""
|
"""Import class from class path."""
|
||||||
module_path, class_name = class_path.rsplit(".", 1)
|
module_path, class_name = class_path.rsplit(".", 1)
|
||||||
module = import_module(module_path)
|
module = import_module(module_path)
|
||||||
return getattr(module, class_name)
|
return getattr(module, class_name)
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,7 @@ async def instantiate_class(
|
||||||
user_id=None,
|
user_id=None,
|
||||||
event_manager: EventManager | None = None,
|
event_manager: EventManager | None = None,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Instantiate class from module type and key, and params"""
|
"""Instantiate class from module type and key, and params."""
|
||||||
|
|
||||||
vertex_type = vertex.vertex_type
|
vertex_type = vertex.vertex_type
|
||||||
base_type = vertex.base_type
|
base_type = vertex.base_type
|
||||||
logger.debug(f"Instantiating {vertex_type} of type {base_type}")
|
logger.debug(f"Instantiating {vertex_type} of type {base_type}")
|
||||||
|
|
@ -77,7 +76,7 @@ def get_params(vertex_params):
|
||||||
|
|
||||||
|
|
||||||
def convert_params_to_sets(params):
|
def convert_params_to_sets(params):
|
||||||
"""Convert certain params to sets"""
|
"""Convert certain params to sets."""
|
||||||
if "allowed_special" in params:
|
if "allowed_special" in params:
|
||||||
params["allowed_special"] = set(params["allowed_special"])
|
params["allowed_special"] = set(params["allowed_special"])
|
||||||
if "disallowed_special" in params:
|
if "disallowed_special" in params:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
def get_memory_key(langchain_object):
|
def get_memory_key(langchain_object):
|
||||||
"""
|
"""Get the memory key from the LangChain object's memory attribute.
|
||||||
|
|
||||||
Given a LangChain object, this function retrieves the current memory key from the object's memory attribute.
|
Given a LangChain object, this function retrieves the current memory key from the object's memory attribute.
|
||||||
It then checks if the key exists in a dictionary of known memory keys and returns the corresponding key,
|
It then checks if the key exists in a dictionary of known memory keys and returns the corresponding key,
|
||||||
or None if the current key is not recognized.
|
or None if the current key is not recognized.
|
||||||
|
|
@ -19,7 +20,8 @@ def get_memory_key(langchain_object):
|
||||||
|
|
||||||
|
|
||||||
def update_memory_keys(langchain_object, possible_new_mem_key):
|
def update_memory_keys(langchain_object, possible_new_mem_key):
|
||||||
"""
|
"""Update the memory keys in the LangChain object's memory attribute.
|
||||||
|
|
||||||
Given a LangChain object and a possible new memory key, this function updates the input and output keys in the
|
Given a LangChain object and a possible new memory key, this function updates the input and output keys in the
|
||||||
object's memory attribute to exclude the current memory key and the possible new key. It then sets the memory key
|
object's memory attribute to exclude the current memory key and the possible new key. It then sets the memory key
|
||||||
to the possible new key.
|
to the possible new key.
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ def load_flow_from_json(
|
||||||
cache: str | None = None,
|
cache: str | None = None,
|
||||||
disable_logs: bool | None = True,
|
disable_logs: bool | None = True,
|
||||||
) -> Graph:
|
) -> Graph:
|
||||||
"""
|
"""Load a flow graph from a JSON file or a JSON object.
|
||||||
Load a flow graph from a JSON file or a JSON object.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
flow (Union[Path, str, dict]): The flow to load. It can be a file path (str or Path object)
|
flow (Union[Path, str, dict]): The flow to load. It can be a file path (str or Path object)
|
||||||
|
|
@ -84,8 +83,7 @@ def run_flow_from_json(
|
||||||
disable_logs: bool | None = True,
|
disable_logs: bool | None = True,
|
||||||
fallback_to_env_vars: bool = False,
|
fallback_to_env_vars: bool = False,
|
||||||
) -> list[RunOutputs]:
|
) -> list[RunOutputs]:
|
||||||
"""
|
"""Run a flow from a JSON file or dictionary.
|
||||||
Run a flow from a JSON file or dictionary.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
flow (Union[Path, str, dict]): The path to the JSON file or the JSON dictionary representing the flow.
|
flow (Union[Path, str, dict]): The path to the JSON file or the JSON dictionary representing the flow.
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@ class UploadError(Exception):
|
||||||
|
|
||||||
|
|
||||||
def upload(file_path: str, host: str, flow_id: str):
|
def upload(file_path: str, host: str, flow_id: str):
|
||||||
"""
|
"""Upload a file to Langflow and return the file path.
|
||||||
Upload a file to Langflow and return the file path.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
file_path (str): The path to the file to be uploaded.
|
file_path (str): The path to the file to be uploaded.
|
||||||
|
|
@ -39,8 +38,7 @@ def upload(file_path: str, host: str, flow_id: str):
|
||||||
|
|
||||||
|
|
||||||
def upload_file(file_path: str, host: str, flow_id: str, components: list[str], tweaks: dict | None = None):
|
def upload_file(file_path: str, host: str, flow_id: str, components: list[str], tweaks: dict | None = None):
|
||||||
"""
|
"""Upload a file to Langflow and return the file path.
|
||||||
Upload a file to Langflow and return the file path.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
file_path (str): The path to the file to be uploaded.
|
file_path (str): The path to the file to be uploaded.
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,10 @@ class SizedLogBuffer:
|
||||||
self,
|
self,
|
||||||
max_readers: int = 20, # max number of concurrent readers for the buffer
|
max_readers: int = 20, # max number of concurrent readers for the buffer
|
||||||
):
|
):
|
||||||
"""
|
"""A buffer for storing log messages for the log retrieval API.
|
||||||
a buffer for storing log messages for the log retrieval API
|
|
||||||
the buffer can be overwritten by an env variable LANGFLOW_LOG_RETRIEVER_BUFFER_SIZE
|
The buffer can be overwritten by an env variable LANGFLOW_LOG_RETRIEVER_BUFFER_SIZE
|
||||||
because the logger is initialized before the settings_service are loaded
|
because the logger is initialized before the settings_service are loaded.
|
||||||
"""
|
"""
|
||||||
self.max: int = 0
|
self.max: int = 0
|
||||||
env_buffer_size = os.getenv("LANGFLOW_LOG_RETRIEVER_BUFFER_SIZE", "0")
|
env_buffer_size = os.getenv("LANGFLOW_LOG_RETRIEVER_BUFFER_SIZE", "0")
|
||||||
|
|
@ -217,9 +217,9 @@ def setup_gunicorn_logger():
|
||||||
|
|
||||||
|
|
||||||
class InterceptHandler(logging.Handler):
|
class InterceptHandler(logging.Handler):
|
||||||
"""
|
"""Default handler from examples in loguru documentation.
|
||||||
Default handler from examples in loguru documentaion.
|
|
||||||
See https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging
|
See https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
|
|
|
||||||
|
|
@ -239,11 +239,11 @@ def setup_sentry(app: FastAPI):
|
||||||
|
|
||||||
|
|
||||||
def setup_static_files(app: FastAPI, static_files_dir: Path):
|
def setup_static_files(app: FastAPI, static_files_dir: Path):
|
||||||
"""
|
"""Setup the static files directory.
|
||||||
Setup the static files directory.
|
|
||||||
Args:
|
Args:
|
||||||
app (FastAPI): FastAPI app.
|
app (FastAPI): FastAPI app.
|
||||||
path (str): Path to the static files directory.
|
static_files_dir (str): Path to the static files directory.
|
||||||
"""
|
"""
|
||||||
app.mount(
|
app.mount(
|
||||||
"/",
|
"/",
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,15 @@ def get_messages(
|
||||||
flow_id: UUID | None = None,
|
flow_id: UUID | None = None,
|
||||||
limit: int | None = None,
|
limit: int | None = None,
|
||||||
) -> list[Message]:
|
) -> list[Message]:
|
||||||
"""
|
"""Retrieves messages from the monitor service based on the provided filters.
|
||||||
Retrieves messages from the monitor service based on the provided filters.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sender (Optional[str]): The sender of the messages (e.g., "Machine" or "User")
|
sender (Optional[str]): The sender of the messages (e.g., "Machine" or "User")
|
||||||
sender_name (Optional[str]): The name of the sender.
|
sender_name (Optional[str]): The name of the sender.
|
||||||
session_id (Optional[str]): The session ID associated with the messages.
|
session_id (Optional[str]): The session ID associated with the messages.
|
||||||
order_by (Optional[str]): The field to order the messages by. Defaults to "timestamp".
|
order_by (Optional[str]): The field to order the messages by. Defaults to "timestamp".
|
||||||
|
order (Optional[str]): The order in which to retrieve the messages. Defaults to "DESC".
|
||||||
|
flow_id (Optional[UUID]): The flow ID associated with the messages.
|
||||||
limit (Optional[int]): The maximum number of messages to retrieve.
|
limit (Optional[int]): The maximum number of messages to retrieve.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -54,10 +55,7 @@ def get_messages(
|
||||||
|
|
||||||
|
|
||||||
def add_messages(messages: Message | list[Message], flow_id: str | None = None):
|
def add_messages(messages: Message | list[Message], flow_id: str | None = None):
|
||||||
"""
|
"""Add a message to the monitor service."""
|
||||||
Add a message to the monitor service.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not isinstance(messages, list):
|
if not isinstance(messages, list):
|
||||||
messages = [messages]
|
messages = [messages]
|
||||||
|
|
||||||
|
|
@ -89,8 +87,7 @@ def add_messagetables(messages: list[MessageTable], session: Session):
|
||||||
|
|
||||||
|
|
||||||
def delete_messages(session_id: str):
|
def delete_messages(session_id: str):
|
||||||
"""
|
"""Delete messages from the monitor service based on the provided session ID.
|
||||||
Delete messages from the monitor service based on the provided session ID.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
session_id (str): The session ID associated with the messages to delete.
|
session_id (str): The session ID associated with the messages to delete.
|
||||||
|
|
@ -107,8 +104,7 @@ def store_message(
|
||||||
message: Message,
|
message: Message,
|
||||||
flow_id: str | None = None,
|
flow_id: str | None = None,
|
||||||
) -> list[Message]:
|
) -> list[Message]:
|
||||||
"""
|
"""Stores a message in the memory.
|
||||||
Stores a message in the memory.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message (Message): The message to store.
|
message (Message): The message to store.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
def setup_callbacks(sync, trace_id, **kwargs):
|
def setup_callbacks(sync, trace_id, **kwargs):
|
||||||
"""Setup callbacks for langchain object"""
|
"""Setup callbacks for langchain object."""
|
||||||
callbacks = []
|
callbacks = []
|
||||||
plugin_service = get_plugins_service()
|
plugin_service = get_plugins_service()
|
||||||
plugin_callbacks = plugin_service.get_callbacks(_id=trace_id)
|
plugin_callbacks = plugin_service.get_callbacks(_id=trace_id)
|
||||||
|
|
@ -37,9 +37,7 @@ def get_langfuse_callback(trace_id):
|
||||||
|
|
||||||
|
|
||||||
def flush_langfuse_callback_if_present(callbacks: list[BaseCallbackHandler | CallbackHandler]):
|
def flush_langfuse_callback_if_present(callbacks: list[BaseCallbackHandler | CallbackHandler]):
|
||||||
"""
|
"""If langfuse callback is present, run callback.langfuse.flush()."""
|
||||||
If langfuse callback is present, run callback.langfuse.flush()
|
|
||||||
"""
|
|
||||||
for callback in callbacks:
|
for callback in callbacks:
|
||||||
if hasattr(callback, "langfuse") and hasattr(callback.langfuse, "flush"):
|
if hasattr(callback, "langfuse") and hasattr(callback.langfuse, "flush"):
|
||||||
callback.langfuse.flush()
|
callback.langfuse.flush()
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ async def run_graph_internal(
|
||||||
inputs: list[InputValueRequest] | None = None,
|
inputs: list[InputValueRequest] | None = None,
|
||||||
outputs: list[str] | None = None,
|
outputs: list[str] | None = None,
|
||||||
) -> tuple[list[RunOutputs], str]:
|
) -> tuple[list[RunOutputs], str]:
|
||||||
"""Run the graph and generate the result"""
|
"""Run the graph and generate the result."""
|
||||||
inputs = inputs or []
|
inputs = inputs or []
|
||||||
session_id_str = flow_id if session_id is None else session_id
|
session_id_str = flow_id if session_id is None else session_id
|
||||||
components = []
|
components = []
|
||||||
|
|
@ -66,8 +66,7 @@ def run_graph(
|
||||||
fallback_to_env_vars: bool = False,
|
fallback_to_env_vars: bool = False,
|
||||||
output_component: str | None = None,
|
output_component: str | None = None,
|
||||||
) -> list[RunOutputs]:
|
) -> list[RunOutputs]:
|
||||||
"""
|
"""Runs the given Langflow Graph with the specified input and returns the outputs.
|
||||||
Runs the given Langflow Graph with the specified input and returns the outputs.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
graph (Graph): The graph to be executed.
|
graph (Graph): The graph to be executed.
|
||||||
|
|
@ -75,6 +74,8 @@ def run_graph(
|
||||||
input_type (str): The type of the input value.
|
input_type (str): The type of the input value.
|
||||||
output_type (str): The type of the desired output.
|
output_type (str): The type of the desired output.
|
||||||
session_id (str | None, optional): The session ID to be used for the flow. Defaults to None.
|
session_id (str | None, optional): The session ID to be used for the flow. Defaults to None.
|
||||||
|
fallback_to_env_vars (bool, optional): Whether to fallback to environment variables.
|
||||||
|
Defaults to False.
|
||||||
output_component (Optional[str], optional): The specific output component to retrieve. Defaults to None.
|
output_component (Optional[str], optional): The specific output component to retrieve. Defaults to None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -157,8 +158,7 @@ def apply_tweaks_on_vertex(vertex: Vertex, node_tweaks: dict[str, Any]) -> None:
|
||||||
def process_tweaks(
|
def process_tweaks(
|
||||||
graph_data: dict[str, Any], tweaks: Tweaks | dict[str, dict[str, Any]], stream: bool = False
|
graph_data: dict[str, Any], tweaks: Tweaks | dict[str, dict[str, Any]], stream: bool = False
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""
|
"""This function is used to tweak the graph data using the node id and the tweaks dict.
|
||||||
This function is used to tweak the graph data using the node id and the tweaks dict.
|
|
||||||
|
|
||||||
:param graph_data: The dictionary containing the graph data. It must contain a 'data' key with
|
:param graph_data: The dictionary containing the graph data. It must contain a 'data' key with
|
||||||
'nodes' as its child or directly contain 'nodes' key. Each node should have an 'id' and 'data'.
|
'nodes' as its child or directly contain 'nodes' key. Each node should have an 'id' and 'data'.
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
class Data(BaseModel):
|
class Data(BaseModel):
|
||||||
"""
|
"""Represents a record with text and optional data.
|
||||||
Represents a record with text and optional data.
|
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
data (dict, optional): Additional data associated with the record.
|
data (dict, optional): Additional data associated with the record.
|
||||||
|
|
@ -45,8 +44,7 @@ class Data(BaseModel):
|
||||||
return {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()}
|
return {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()}
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
"""
|
"""Retrieves the text value from the data dictionary.
|
||||||
Retrieves the text value from the data dictionary.
|
|
||||||
|
|
||||||
If the text key is present in the data dictionary, the corresponding value is returned.
|
If the text key is present in the data dictionary, the corresponding value is returned.
|
||||||
Otherwise, the default value is returned.
|
Otherwise, the default value is returned.
|
||||||
|
|
@ -58,8 +56,7 @@ class Data(BaseModel):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_document(cls, document: Document) -> "Data":
|
def from_document(cls, document: Document) -> "Data":
|
||||||
"""
|
"""Converts a Document to a Data.
|
||||||
Converts a Document to a Data.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
document (Document): The Document to convert.
|
document (Document): The Document to convert.
|
||||||
|
|
@ -73,8 +70,7 @@ class Data(BaseModel):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_lc_message(cls, message: BaseMessage) -> "Data":
|
def from_lc_message(cls, message: BaseMessage) -> "Data":
|
||||||
"""
|
"""Converts a BaseMessage to a Data.
|
||||||
Converts a BaseMessage to a Data.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message (BaseMessage): The BaseMessage to convert.
|
message (BaseMessage): The BaseMessage to convert.
|
||||||
|
|
@ -87,7 +83,8 @@ class Data(BaseModel):
|
||||||
return cls(data=data, text_key="text")
|
return cls(data=data, text_key="text")
|
||||||
|
|
||||||
def __add__(self, other: "Data") -> "Data":
|
def __add__(self, other: "Data") -> "Data":
|
||||||
"""
|
"""Combines the data of two data by attempting to add values for overlapping keys.
|
||||||
|
|
||||||
Combines the data of two data by attempting to add values for overlapping keys
|
Combines the data of two data by attempting to add values for overlapping keys
|
||||||
for all types that support the addition operation. Falls back to the value from 'other'
|
for all types that support the addition operation. Falls back to the value from 'other'
|
||||||
record when addition is not supported.
|
record when addition is not supported.
|
||||||
|
|
@ -108,8 +105,7 @@ class Data(BaseModel):
|
||||||
return Data(data=combined_data)
|
return Data(data=combined_data)
|
||||||
|
|
||||||
def to_lc_document(self) -> Document:
|
def to_lc_document(self) -> Document:
|
||||||
"""
|
"""Converts the Data to a Document.
|
||||||
Converts the Data to a Document.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Document: The converted Document.
|
Document: The converted Document.
|
||||||
|
|
@ -121,8 +117,7 @@ class Data(BaseModel):
|
||||||
def to_lc_message(
|
def to_lc_message(
|
||||||
self,
|
self,
|
||||||
) -> BaseMessage:
|
) -> BaseMessage:
|
||||||
"""
|
"""Converts the Data to a BaseMessage.
|
||||||
Converts the Data to a BaseMessage.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BaseMessage: The converted BaseMessage.
|
BaseMessage: The converted BaseMessage.
|
||||||
|
|
@ -158,9 +153,7 @@ class Data(BaseModel):
|
||||||
return AIMessage(content=text)
|
return AIMessage(content=text)
|
||||||
|
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
"""
|
"""Allows attribute-like access to the data dictionary."""
|
||||||
Allows attribute-like access to the data dictionary.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
if key.startswith("__"):
|
if key.startswith("__"):
|
||||||
return self.__getattribute__(key)
|
return self.__getattribute__(key)
|
||||||
|
|
@ -173,8 +166,9 @@ class Data(BaseModel):
|
||||||
raise AttributeError(msg) from e
|
raise AttributeError(msg) from e
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
"""
|
"""Set attribute-like values in the data dictionary.
|
||||||
Allows attribute-like setting of values in the data dictionary,
|
|
||||||
|
Allows attribute-like setting of values in the data dictionary.
|
||||||
while still allowing direct assignment to class attributes.
|
while still allowing direct assignment to class attributes.
|
||||||
"""
|
"""
|
||||||
if key in {"data", "text_key"} or key.startswith("_"):
|
if key in {"data", "text_key"} or key.startswith("_"):
|
||||||
|
|
@ -186,18 +180,14 @@ class Data(BaseModel):
|
||||||
self.data[key] = value
|
self.data[key] = value
|
||||||
|
|
||||||
def __delattr__(self, key):
|
def __delattr__(self, key):
|
||||||
"""
|
"""Allows attribute-like deletion from the data dictionary."""
|
||||||
Allows attribute-like deletion from the data dictionary.
|
|
||||||
"""
|
|
||||||
if key in {"data", "text_key"} or key.startswith("_"):
|
if key in {"data", "text_key"} or key.startswith("_"):
|
||||||
super().__delattr__(key)
|
super().__delattr__(key)
|
||||||
else:
|
else:
|
||||||
del self.data[key]
|
del self.data[key]
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
"""
|
"""Custom deepcopy implementation to handle copying of the Data object."""
|
||||||
Custom deepcopy implementation to handle copying of the Data object.
|
|
||||||
"""
|
|
||||||
# Create a new Data object with a deep copy of the data dictionary
|
# Create a new Data object with a deep copy of the data dictionary
|
||||||
return Data(data=copy.deepcopy(self.data, memo), text_key=self.text_key, default_value=self.default_value)
|
return Data(data=copy.deepcopy(self.data, memo), text_key=self.text_key, default_value=self.default_value)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
class dotdict(dict):
|
class dotdict(dict):
|
||||||
"""
|
"""dotdict allows accessing dictionary elements using dot notation (e.g., dict.key instead of dict['key']).
|
||||||
dotdict allows accessing dictionary elements using dot notation (e.g., dict.key instead of dict['key']).
|
|
||||||
It automatically converts nested dictionaries into dotdict instances, enabling dot notation on them as well.
|
It automatically converts nested dictionaries into dotdict instances, enabling dot notation on them as well.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
|
|
@ -11,8 +11,7 @@ class dotdict(dict):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
"""
|
"""Override dot access to behave like dictionary lookup. Automatically convert nested dicts to dotdicts.
|
||||||
Override dot access to behave like dictionary lookup. Automatically convert nested dicts to dotdicts.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
attr (str): Attribute to access.
|
attr (str): Attribute to access.
|
||||||
|
|
@ -35,8 +34,7 @@ class dotdict(dict):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
"""
|
"""Override attribute setting to work as dictionary item assignment.
|
||||||
Override attribute setting to work as dictionary item assignment.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key (str): The key under which to store the value.
|
key (str): The key under which to store the value.
|
||||||
|
|
@ -47,8 +45,7 @@ class dotdict(dict):
|
||||||
self[key] = value
|
self[key] = value
|
||||||
|
|
||||||
def __delattr__(self, key):
|
def __delattr__(self, key):
|
||||||
"""
|
"""Override attribute deletion to work as dictionary item deletion.
|
||||||
Override attribute deletion to work as dictionary item deletion.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key (str): The key of the item to delete from the dictionary.
|
key (str): The key of the item to delete from the dictionary.
|
||||||
|
|
@ -63,8 +60,7 @@ class dotdict(dict):
|
||||||
raise AttributeError(msg) from e
|
raise AttributeError(msg) from e
|
||||||
|
|
||||||
def __missing__(self, key):
|
def __missing__(self, key):
|
||||||
"""
|
"""Handle missing keys by returning an empty dotdict. This allows chaining access without raising KeyError.
|
||||||
Handle missing keys by returning an empty dotdict. This allows chaining access without raising KeyError.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The missing key.
|
key: The missing key.
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,7 @@ class Message(Data):
|
||||||
def to_lc_message(
|
def to_lc_message(
|
||||||
self,
|
self,
|
||||||
) -> BaseMessage:
|
) -> BaseMessage:
|
||||||
"""
|
"""Converts the Data to a BaseMessage.
|
||||||
Converts the Data to a BaseMessage.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BaseMessage: The converted BaseMessage.
|
BaseMessage: The converted BaseMessage.
|
||||||
|
|
@ -139,16 +138,14 @@ class Message(Data):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_data(cls, data: Data) -> Message:
|
def from_data(cls, data: Data) -> Message:
|
||||||
"""
|
"""Converts Data to a Message.
|
||||||
Converts a BaseMessage to a Data.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
record (BaseMessage): The BaseMessage to convert.
|
data: The Data to convert.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Data: The converted Data.
|
The converted Message.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
text=data.text,
|
text=data.text,
|
||||||
sender=data.sender,
|
sender=data.sender,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ class LangflowUvicornWorker(UvicornWorker):
|
||||||
- https://github.com/encode/uvicorn/issues/1116
|
- https://github.com/encode/uvicorn/issues/1116
|
||||||
- https://github.com/benoitc/gunicorn/issues/2604
|
- https://github.com/benoitc/gunicorn/issues/2604
|
||||||
"""
|
"""
|
||||||
|
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
loop.add_signal_handler(signal.SIGINT, self.handle_exit, signal.SIGINT, None)
|
loop.add_signal_handler(signal.SIGINT, self.handle_exit, signal.SIGINT, None)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ class Service(ABC):
|
||||||
|
|
||||||
def get_schema(self):
|
def get_schema(self):
|
||||||
"""Build a dictionary listing all methods, their parameters, types, return types and documentation."""
|
"""Build a dictionary listing all methods, their parameters, types, return types and documentation."""
|
||||||
|
|
||||||
schema = {}
|
schema = {}
|
||||||
ignore = ["teardown", "set_ready"]
|
ignore = ["teardown", "set_ready"]
|
||||||
for method in dir(self):
|
for method in dir(self):
|
||||||
|
|
|
||||||
63
src/backend/base/langflow/services/cache/base.py
vendored
63
src/backend/base/langflow/services/cache/base.py
vendored
|
|
@ -10,19 +10,17 @@ AsyncLockType = TypeVar("AsyncLockType", bound=asyncio.Lock)
|
||||||
|
|
||||||
|
|
||||||
class CacheService(Service, Generic[LockType]):
|
class CacheService(Service, Generic[LockType]):
|
||||||
"""
|
"""Abstract base class for a cache."""
|
||||||
Abstract base class for a cache.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name = "cache_service"
|
name = "cache_service"
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get(self, key, lock: LockType | None = None):
|
def get(self, key, lock: LockType | None = None):
|
||||||
"""
|
"""Retrieve an item from the cache.
|
||||||
Retrieve an item from the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to retrieve.
|
key: The key of the item to retrieve.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The value associated with the key, or None if the key is not found.
|
The value associated with the key, or None if the key is not found.
|
||||||
|
|
@ -30,43 +28,40 @@ class CacheService(Service, Generic[LockType]):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def set(self, key, value, lock: LockType | None = None):
|
def set(self, key, value, lock: LockType | None = None):
|
||||||
"""
|
"""Add an item to the cache.
|
||||||
Add an item to the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
value: The value to cache.
|
value: The value to cache.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def upsert(self, key, value, lock: LockType | None = None):
|
def upsert(self, key, value, lock: LockType | None = None):
|
||||||
"""
|
"""Add an item to the cache if it doesn't exist, or update it if it does.
|
||||||
Add an item to the cache if it doesn't exist, or update it if it does.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
value: The value to cache.
|
value: The value to cache.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def delete(self, key, lock: LockType | None = None):
|
def delete(self, key, lock: LockType | None = None):
|
||||||
"""
|
"""Remove an item from the cache.
|
||||||
Remove an item from the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to remove.
|
key: The key of the item to remove.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def clear(self, lock: LockType | None = None):
|
def clear(self, lock: LockType | None = None):
|
||||||
"""
|
"""Clear all items from the cache."""
|
||||||
Clear all items from the cache.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
"""
|
"""Check if the key is in the cache.
|
||||||
Check if the key is in the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to check.
|
key: The key of the item to check.
|
||||||
|
|
@ -77,8 +72,7 @@ class CacheService(Service, Generic[LockType]):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
"""
|
"""Retrieve an item from the cache using the square bracket notation.
|
||||||
Retrieve an item from the cache using the square bracket notation.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to retrieve.
|
key: The key of the item to retrieve.
|
||||||
|
|
@ -86,8 +80,7 @@ class CacheService(Service, Generic[LockType]):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
"""
|
"""Add an item to the cache using the square bracket notation.
|
||||||
Add an item to the cache using the square bracket notation.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
|
|
@ -96,8 +89,7 @@ class CacheService(Service, Generic[LockType]):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
"""
|
"""Remove an item from the cache using the square bracket notation.
|
||||||
Remove an item from the cache using the square bracket notation.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to remove.
|
key: The key of the item to remove.
|
||||||
|
|
@ -105,19 +97,17 @@ class CacheService(Service, Generic[LockType]):
|
||||||
|
|
||||||
|
|
||||||
class AsyncBaseCacheService(Service, Generic[AsyncLockType]):
|
class AsyncBaseCacheService(Service, Generic[AsyncLockType]):
|
||||||
"""
|
"""Abstract base class for a async cache."""
|
||||||
Abstract base class for a async cache.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name = "cache_service"
|
name = "cache_service"
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
async def get(self, key, lock: AsyncLockType | None = None):
|
async def get(self, key, lock: AsyncLockType | None = None):
|
||||||
"""
|
"""Retrieve an item from the cache.
|
||||||
Retrieve an item from the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to retrieve.
|
key: The key of the item to retrieve.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The value associated with the key, or None if the key is not found.
|
The value associated with the key, or None if the key is not found.
|
||||||
|
|
@ -125,43 +115,40 @@ class AsyncBaseCacheService(Service, Generic[AsyncLockType]):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
async def set(self, key, value, lock: AsyncLockType | None = None):
|
async def set(self, key, value, lock: AsyncLockType | None = None):
|
||||||
"""
|
"""Add an item to the cache.
|
||||||
Add an item to the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
value: The value to cache.
|
value: The value to cache.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
async def upsert(self, key, value, lock: AsyncLockType | None = None):
|
async def upsert(self, key, value, lock: AsyncLockType | None = None):
|
||||||
"""
|
"""Add an item to the cache if it doesn't exist, or update it if it does.
|
||||||
Add an item to the cache if it doesn't exist, or update it if it does.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
value: The value to cache.
|
value: The value to cache.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
async def delete(self, key, lock: AsyncLockType | None = None):
|
async def delete(self, key, lock: AsyncLockType | None = None):
|
||||||
"""
|
"""Remove an item from the cache.
|
||||||
Remove an item from the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to remove.
|
key: The key of the item to remove.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
async def clear(self, lock: AsyncLockType | None = None):
|
async def clear(self, lock: AsyncLockType | None = None):
|
||||||
"""
|
"""Clear all items from the cache."""
|
||||||
Clear all items from the cache.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
"""
|
"""Check if the key is in the cache.
|
||||||
Check if the key is in the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to check.
|
key: The key of the item to check.
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ from langflow.services.cache.utils import CACHE_MISS
|
||||||
|
|
||||||
|
|
||||||
class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
"""
|
"""A simple in-memory cache using an OrderedDict.
|
||||||
A simple in-memory cache using an OrderedDict.
|
|
||||||
|
|
||||||
This cache supports setting a maximum size and expiration time for cached items.
|
This cache supports setting a maximum size and expiration time for cached items.
|
||||||
When the cache is full, it uses a Least Recently Used (LRU) eviction policy.
|
When the cache is full, it uses a Least Recently Used (LRU) eviction policy.
|
||||||
|
|
@ -24,7 +23,6 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
expiration_time (int, optional): Time in seconds after which a cached item expires. Default is 1 hour.
|
expiration_time (int, optional): Time in seconds after which a cached item expires. Default is 1 hour.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
cache = InMemoryCache(max_size=3, expiration_time=5)
|
cache = InMemoryCache(max_size=3, expiration_time=5)
|
||||||
|
|
||||||
# setting cache values
|
# setting cache values
|
||||||
|
|
@ -38,8 +36,7 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, max_size=None, expiration_time=60 * 60):
|
def __init__(self, max_size=None, expiration_time=60 * 60):
|
||||||
"""
|
"""Initialize a new InMemoryCache instance.
|
||||||
Initialize a new InMemoryCache instance.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
max_size (int, optional): Maximum number of items to store in the cache.
|
max_size (int, optional): Maximum number of items to store in the cache.
|
||||||
|
|
@ -51,11 +48,11 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
self.expiration_time = expiration_time
|
self.expiration_time = expiration_time
|
||||||
|
|
||||||
def get(self, key, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
def get(self, key, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
||||||
"""
|
"""Retrieve an item from the cache.
|
||||||
Retrieve an item from the cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item to retrieve.
|
key: The key of the item to retrieve.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The value associated with the key, or None if the key is not found or the item has expired.
|
The value associated with the key, or None if the key is not found or the item has expired.
|
||||||
|
|
@ -64,9 +61,7 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
return self._get_without_lock(key)
|
return self._get_without_lock(key)
|
||||||
|
|
||||||
def _get_without_lock(self, key):
|
def _get_without_lock(self, key):
|
||||||
"""
|
"""Retrieve an item from the cache without acquiring the lock."""
|
||||||
Retrieve an item from the cache without acquiring the lock.
|
|
||||||
"""
|
|
||||||
if item := self._cache.get(key):
|
if item := self._cache.get(key):
|
||||||
if self.expiration_time is None or time.time() - item["time"] < self.expiration_time:
|
if self.expiration_time is None or time.time() - item["time"] < self.expiration_time:
|
||||||
# Move the key to the end to make it recently used
|
# Move the key to the end to make it recently used
|
||||||
|
|
@ -77,14 +72,14 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set(self, key, value, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
def set(self, key, value, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
||||||
"""
|
"""Add an item to the cache.
|
||||||
Add an item to the cache.
|
|
||||||
|
|
||||||
If the cache is full, the least recently used item is evicted.
|
If the cache is full, the least recently used item is evicted.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
value: The value to cache.
|
value: The value to cache.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
with lock or self._lock:
|
with lock or self._lock:
|
||||||
if key in self._cache:
|
if key in self._cache:
|
||||||
|
|
@ -98,13 +93,14 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
self._cache[key] = {"value": value, "time": time.time()}
|
self._cache[key] = {"value": value, "time": time.time()}
|
||||||
|
|
||||||
def upsert(self, key, value, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
def upsert(self, key, value, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
||||||
"""
|
"""Inserts or updates a value in the cache.
|
||||||
Inserts or updates a value in the cache.
|
|
||||||
If the existing value and the new value are both dictionaries, they are merged.
|
If the existing value and the new value are both dictionaries, they are merged.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
value: The value to insert or update.
|
value: The value to insert or update.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
with lock or self._lock:
|
with lock or self._lock:
|
||||||
existing_value = self._get_without_lock(key)
|
existing_value = self._get_without_lock(key)
|
||||||
|
|
@ -115,13 +111,14 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
self.set(key, value)
|
self.set(key, value)
|
||||||
|
|
||||||
def get_or_set(self, key, value, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
def get_or_set(self, key, value, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
||||||
"""
|
"""Retrieve an item from the cache.
|
||||||
Retrieve an item from the cache. If the item does not exist,
|
|
||||||
set it with the provided value.
|
If the item does not exist, set it with the provided value.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
value: The value to cache if the item doesn't exist.
|
value: The value to cache if the item doesn't exist.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The cached value associated with the key.
|
The cached value associated with the key.
|
||||||
|
|
@ -133,19 +130,11 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def delete(self, key, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
def delete(self, key, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
||||||
"""
|
|
||||||
Remove an item from the cache.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key: The key of the item to remove.
|
|
||||||
"""
|
|
||||||
with lock or self._lock:
|
with lock or self._lock:
|
||||||
self._cache.pop(key, None)
|
self._cache.pop(key, None)
|
||||||
|
|
||||||
def clear(self, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
def clear(self, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
||||||
"""
|
"""Clear all items from the cache."""
|
||||||
Clear all items from the cache.
|
|
||||||
"""
|
|
||||||
with lock or self._lock:
|
with lock or self._lock:
|
||||||
self._cache.clear()
|
self._cache.clear()
|
||||||
|
|
||||||
|
|
@ -175,8 +164,7 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
||||||
|
|
||||||
|
|
||||||
class RedisCache(AsyncBaseCacheService, Generic[LockType]):
|
class RedisCache(AsyncBaseCacheService, Generic[LockType]):
|
||||||
"""
|
"""A Redis-based cache implementation.
|
||||||
A Redis-based cache implementation.
|
|
||||||
|
|
||||||
This cache supports setting an expiration time for cached items.
|
This cache supports setting an expiration time for cached items.
|
||||||
|
|
||||||
|
|
@ -184,7 +172,6 @@ class RedisCache(AsyncBaseCacheService, Generic[LockType]):
|
||||||
expiration_time (int, optional): Time in seconds after which a cached item expires. Default is 1 hour.
|
expiration_time (int, optional): Time in seconds after which a cached item expires. Default is 1 hour.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
cache = RedisCache(expiration_time=5)
|
cache = RedisCache(expiration_time=5)
|
||||||
|
|
||||||
# setting cache values
|
# setting cache values
|
||||||
|
|
@ -198,15 +185,15 @@ class RedisCache(AsyncBaseCacheService, Generic[LockType]):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, host="localhost", port=6379, db=0, url=None, expiration_time=60 * 60):
|
def __init__(self, host="localhost", port=6379, db=0, url=None, expiration_time=60 * 60):
|
||||||
"""
|
"""Initialize a new RedisCache instance.
|
||||||
Initialize a new RedisCache instance.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
host (str, optional): Redis host.
|
host (str, optional): Redis host.
|
||||||
port (int, optional): Redis port.
|
port (int, optional): Redis port.
|
||||||
db (int, optional): Redis DB.
|
db (int, optional): Redis DB.
|
||||||
|
url (str, optional): Redis URL.
|
||||||
expiration_time (int, optional): Time in seconds after which a
|
expiration_time (int, optional): Time in seconds after which a
|
||||||
ached item expires. Default is 1 hour.
|
cached item expires. Default is 1 hour.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
import redis
|
import redis
|
||||||
|
|
@ -228,9 +215,7 @@ class RedisCache(AsyncBaseCacheService, Generic[LockType]):
|
||||||
|
|
||||||
# check connection
|
# check connection
|
||||||
def is_connected(self):
|
def is_connected(self):
|
||||||
"""
|
"""Check if the Redis client is connected."""
|
||||||
Check if the Redis client is connected.
|
|
||||||
"""
|
|
||||||
import redis
|
import redis
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -241,28 +226,12 @@ class RedisCache(AsyncBaseCacheService, Generic[LockType]):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def get(self, key, lock=None):
|
async def get(self, key, lock=None):
|
||||||
"""
|
|
||||||
Retrieve an item from the cache.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key: The key of the item to retrieve.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The value associated with the key, or None if the key is not found.
|
|
||||||
"""
|
|
||||||
if key is None:
|
if key is None:
|
||||||
return None
|
return None
|
||||||
value = self._client.get(str(key))
|
value = self._client.get(str(key))
|
||||||
return pickle.loads(value) if value else None
|
return pickle.loads(value) if value else None
|
||||||
|
|
||||||
async def set(self, key, value, lock=None):
|
async def set(self, key, value, lock=None):
|
||||||
"""
|
|
||||||
Add an item to the cache.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key: The key of the item.
|
|
||||||
value: The value to cache.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
if pickled := pickle.dumps(value):
|
if pickled := pickle.dumps(value):
|
||||||
result = self._client.setex(str(key), self.expiration_time, pickled)
|
result = self._client.setex(str(key), self.expiration_time, pickled)
|
||||||
|
|
@ -274,13 +243,14 @@ class RedisCache(AsyncBaseCacheService, Generic[LockType]):
|
||||||
raise TypeError(msg) from exc
|
raise TypeError(msg) from exc
|
||||||
|
|
||||||
async def upsert(self, key, value, lock=None):
|
async def upsert(self, key, value, lock=None):
|
||||||
"""
|
"""Inserts or updates a value in the cache.
|
||||||
Inserts or updates a value in the cache.
|
|
||||||
If the existing value and the new value are both dictionaries, they are merged.
|
If the existing value and the new value are both dictionaries, they are merged.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: The key of the item.
|
key: The key of the item.
|
||||||
value: The value to insert or update.
|
value: The value to insert or update.
|
||||||
|
lock: A lock to use for the operation.
|
||||||
"""
|
"""
|
||||||
if key is None:
|
if key is None:
|
||||||
return
|
return
|
||||||
|
|
@ -292,18 +262,10 @@ class RedisCache(AsyncBaseCacheService, Generic[LockType]):
|
||||||
await self.set(key, value)
|
await self.set(key, value)
|
||||||
|
|
||||||
async def delete(self, key, lock=None):
|
async def delete(self, key, lock=None):
|
||||||
"""
|
|
||||||
Remove an item from the cache.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key: The key of the item to remove.
|
|
||||||
"""
|
|
||||||
self._client.delete(key)
|
self._client.delete(key)
|
||||||
|
|
||||||
async def clear(self, lock=None):
|
async def clear(self, lock=None):
|
||||||
"""
|
"""Clear all items from the cache."""
|
||||||
Clear all items from the cache.
|
|
||||||
"""
|
|
||||||
self._client.flushdb()
|
self._client.flushdb()
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,12 @@ def filter_json(json_data):
|
||||||
|
|
||||||
@create_cache_folder
|
@create_cache_folder
|
||||||
def save_binary_file(content: str, file_name: str, accepted_types: list[str]) -> str:
|
def save_binary_file(content: str, file_name: str, accepted_types: list[str]) -> str:
|
||||||
"""
|
"""Save a binary file to the specified folder.
|
||||||
Save a binary file to the specified folder.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
content: The content of the file as a bytes object.
|
content: The content of the file as a bytes object.
|
||||||
file_name: The name of the file, including its extension.
|
file_name: The name of the file, including its extension.
|
||||||
|
accepted_types: A list of accepted file types.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The path to the saved file.
|
The path to the saved file.
|
||||||
|
|
@ -112,8 +112,7 @@ def save_binary_file(content: str, file_name: str, accepted_types: list[str]) ->
|
||||||
|
|
||||||
@create_cache_folder
|
@create_cache_folder
|
||||||
def save_uploaded_file(file: UploadFile, folder_name):
|
def save_uploaded_file(file: UploadFile, folder_name):
|
||||||
"""
|
"""Save an uploaded file to the specified folder with a hash of its content as the file name.
|
||||||
Save an uploaded file to the specified folder with a hash of its content as the file name.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
file: The uploaded file object.
|
file: The uploaded file object.
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,7 @@ class CacheService(Subject, Service):
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def set_client_id(self, client_id: str):
|
def set_client_id(self, client_id: str):
|
||||||
"""
|
"""Context manager to set the current client_id and associated cache.
|
||||||
Context manager to set the current client_id and associated cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
client_id (str): The client identifier.
|
client_id (str): The client identifier.
|
||||||
|
|
@ -81,13 +80,13 @@ class CacheService(Subject, Service):
|
||||||
self.current_cache = self._cache.get(self.current_client_id, {})
|
self.current_cache = self._cache.get(self.current_client_id, {})
|
||||||
|
|
||||||
def add(self, name: str, obj: Any, obj_type: str, extension: str | None = None):
|
def add(self, name: str, obj: Any, obj_type: str, extension: str | None = None):
|
||||||
"""
|
"""Add an object to the current client's cache.
|
||||||
Add an object to the current client's cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The cache key.
|
name (str): The cache key.
|
||||||
obj (Any): The object to cache.
|
obj (Any): The object to cache.
|
||||||
obj_type (str): The type of the object.
|
obj_type (str): The type of the object.
|
||||||
|
extension: The file extension of the object.
|
||||||
"""
|
"""
|
||||||
object_extensions = {
|
object_extensions = {
|
||||||
"image": "png",
|
"image": "png",
|
||||||
|
|
@ -102,8 +101,7 @@ class CacheService(Subject, Service):
|
||||||
self.notify()
|
self.notify()
|
||||||
|
|
||||||
def add_pandas(self, name: str, obj: Any):
|
def add_pandas(self, name: str, obj: Any):
|
||||||
"""
|
"""Add a pandas DataFrame or Series to the current client's cache.
|
||||||
Add a pandas DataFrame or Series to the current client's cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The cache key.
|
name (str): The cache key.
|
||||||
|
|
@ -116,12 +114,12 @@ class CacheService(Subject, Service):
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
|
|
||||||
def add_image(self, name: str, obj: Any, extension: str = "png"):
|
def add_image(self, name: str, obj: Any, extension: str = "png"):
|
||||||
"""
|
"""Add a PIL Image to the current client's cache.
|
||||||
Add a PIL Image to the current client's cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The cache key.
|
name (str): The cache key.
|
||||||
obj (Any): The PIL Image object.
|
obj (Any): The PIL Image object.
|
||||||
|
extension: The file extension of the image.
|
||||||
"""
|
"""
|
||||||
if isinstance(obj, Image.Image):
|
if isinstance(obj, Image.Image):
|
||||||
self.add(name, obj, "image", extension=extension)
|
self.add(name, obj, "image", extension=extension)
|
||||||
|
|
@ -130,8 +128,7 @@ class CacheService(Subject, Service):
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
|
|
||||||
def get(self, name: str):
|
def get(self, name: str):
|
||||||
"""
|
"""Get an object from the current client's cache.
|
||||||
Get an object from the current client's cache.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The cache key.
|
name (str): The cache key.
|
||||||
|
|
@ -142,8 +139,7 @@ class CacheService(Subject, Service):
|
||||||
return self.current_cache[name]
|
return self.current_cache[name]
|
||||||
|
|
||||||
def get_last(self):
|
def get_last(self):
|
||||||
"""
|
"""Get the last added item in the current client's cache.
|
||||||
Get the last added item in the current client's cache.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The last added item in the cache.
|
The last added item in the cache.
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,7 @@ from langflow.services.deps import get_cache_service
|
||||||
|
|
||||||
|
|
||||||
class ChatService(Service):
|
class ChatService(Service):
|
||||||
"""
|
"""Service class for managing chat-related operations."""
|
||||||
Service class for managing chat-related operations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name = "chat_service"
|
name = "chat_service"
|
||||||
|
|
||||||
|
|
@ -21,8 +19,7 @@ class ChatService(Service):
|
||||||
self.cache_service = get_cache_service()
|
self.cache_service = get_cache_service()
|
||||||
|
|
||||||
def _get_lock(self, key: str):
|
def _get_lock(self, key: str):
|
||||||
"""
|
"""Retrieves the lock associated with the given key.
|
||||||
Retrieves the lock associated with the given key.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key (str): The key to retrieve the lock for.
|
key (str): The key to retrieve the lock for.
|
||||||
|
|
@ -37,8 +34,7 @@ class ChatService(Service):
|
||||||
async def _perform_cache_operation(
|
async def _perform_cache_operation(
|
||||||
self, operation: str, key: str, data: Any = None, lock: asyncio.Lock | None = None
|
self, operation: str, key: str, data: Any = None, lock: asyncio.Lock | None = None
|
||||||
):
|
):
|
||||||
"""
|
"""Perform a cache operation based on the given operation type.
|
||||||
Perform a cache operation based on the given operation type.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
operation (str): The type of cache operation to perform. Possible values are "upsert", "get", or "delete".
|
operation (str): The type of cache operation to perform. Possible values are "upsert", "get", or "delete".
|
||||||
|
|
@ -76,8 +72,7 @@ class ChatService(Service):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def set_cache(self, key: str, data: Any, lock: asyncio.Lock | None = None) -> bool:
|
async def set_cache(self, key: str, data: Any, lock: asyncio.Lock | None = None) -> bool:
|
||||||
"""
|
"""Set the cache for a client.
|
||||||
Set the cache for a client.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key (str): The cache key.
|
key (str): The cache key.
|
||||||
|
|
@ -95,8 +90,7 @@ class ChatService(Service):
|
||||||
return key in self.cache_service
|
return key in self.cache_service
|
||||||
|
|
||||||
async def get_cache(self, key: str, lock: asyncio.Lock | None = None) -> Any:
|
async def get_cache(self, key: str, lock: asyncio.Lock | None = None) -> Any:
|
||||||
"""
|
"""Get the cache for a client.
|
||||||
Get the cache for a client.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key (str): The cache key.
|
key (str): The cache key.
|
||||||
|
|
@ -108,8 +102,7 @@ class ChatService(Service):
|
||||||
return await self._perform_cache_operation("get", key, lock=lock or self._get_lock(key))
|
return await self._perform_cache_operation("get", key, lock=lock or self._get_lock(key))
|
||||||
|
|
||||||
async def clear_cache(self, key: str, lock: asyncio.Lock | None = None):
|
async def clear_cache(self, key: str, lock: asyncio.Lock | None = None):
|
||||||
"""
|
"""Clear the cache for a client.
|
||||||
Clear the cache for a client.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key (str): The cache key.
|
key (str): The cache key.
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ from .model import Flow
|
||||||
|
|
||||||
def get_flow_by_id(session: Session = Depends(get_session), flow_id: str | None = None) -> Flow | None:
|
def get_flow_by_id(session: Session = Depends(get_session), flow_id: str | None = None) -> Flow | None:
|
||||||
"""Get flow by id."""
|
"""Get flow by id."""
|
||||||
|
|
||||||
if flow_id is None:
|
if flow_id is None:
|
||||||
msg = "Flow id is required."
|
msg = "Flow id is required."
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
@ -19,7 +18,6 @@ def get_flow_by_id(session: Session = Depends(get_session), flow_id: str | None
|
||||||
|
|
||||||
def get_webhook_component_in_flow(flow_data: dict):
|
def get_webhook_component_in_flow(flow_data: dict):
|
||||||
"""Get webhook component in flow data."""
|
"""Get webhook component in flow data."""
|
||||||
|
|
||||||
for node in flow_data.get("nodes", []):
|
for node in flow_data.get("nodes", []):
|
||||||
if "Webhook" in node.get("id"):
|
if "Webhook" in node.get("id"):
|
||||||
return node
|
return node
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,12 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
|
|
||||||
def get_service(service_type: ServiceType, default=None):
|
def get_service(service_type: ServiceType, default=None):
|
||||||
"""
|
"""Retrieves the service instance for the given service type.
|
||||||
Retrieves the service instance for the given service type.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
service_type (ServiceType): The type of service to retrieve.
|
service_type (ServiceType): The type of service to retrieve.
|
||||||
|
default (ServiceFactory, optional): The default ServiceFactory to use if the service is not found.
|
||||||
|
Defaults to None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Any: The service instance.
|
Any: The service instance.
|
||||||
|
|
@ -49,8 +50,7 @@ def get_service(service_type: ServiceType, default=None):
|
||||||
|
|
||||||
|
|
||||||
def get_telemetry_service() -> TelemetryService:
|
def get_telemetry_service() -> TelemetryService:
|
||||||
"""
|
"""Retrieves the TelemetryService instance from the service manager.
|
||||||
Retrieves the TelemetryService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
TelemetryService: The TelemetryService instance.
|
TelemetryService: The TelemetryService instance.
|
||||||
|
|
@ -61,8 +61,7 @@ def get_telemetry_service() -> TelemetryService:
|
||||||
|
|
||||||
|
|
||||||
def get_tracing_service() -> TracingService:
|
def get_tracing_service() -> TracingService:
|
||||||
"""
|
"""Retrieves the TracingService instance from the service manager.
|
||||||
Retrieves the TracingService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
TracingService: The TracingService instance.
|
TracingService: The TracingService instance.
|
||||||
|
|
@ -73,8 +72,7 @@ def get_tracing_service() -> TracingService:
|
||||||
|
|
||||||
|
|
||||||
def get_state_service() -> StateService:
|
def get_state_service() -> StateService:
|
||||||
"""
|
"""Retrieves the StateService instance from the service manager.
|
||||||
Retrieves the StateService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The StateService instance.
|
The StateService instance.
|
||||||
|
|
@ -85,8 +83,7 @@ def get_state_service() -> StateService:
|
||||||
|
|
||||||
|
|
||||||
def get_socket_service() -> SocketIOService:
|
def get_socket_service() -> SocketIOService:
|
||||||
"""
|
"""Get the SocketIOService instance from the service manager.
|
||||||
Get the SocketIOService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
SocketIOService: The SocketIOService instance.
|
SocketIOService: The SocketIOService instance.
|
||||||
|
|
@ -95,8 +92,7 @@ def get_socket_service() -> SocketIOService:
|
||||||
|
|
||||||
|
|
||||||
def get_storage_service() -> StorageService:
|
def get_storage_service() -> StorageService:
|
||||||
"""
|
"""Retrieves the storage service instance.
|
||||||
Retrieves the storage service instance.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The storage service instance.
|
The storage service instance.
|
||||||
|
|
@ -107,8 +103,7 @@ def get_storage_service() -> StorageService:
|
||||||
|
|
||||||
|
|
||||||
def get_variable_service() -> VariableService:
|
def get_variable_service() -> VariableService:
|
||||||
"""
|
"""Retrieves the VariableService instance from the service manager.
|
||||||
Retrieves the VariableService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The VariableService instance.
|
The VariableService instance.
|
||||||
|
|
@ -120,8 +115,7 @@ def get_variable_service() -> VariableService:
|
||||||
|
|
||||||
|
|
||||||
def get_plugins_service() -> PluginService:
|
def get_plugins_service() -> PluginService:
|
||||||
"""
|
"""Get the PluginService instance from the service manager.
|
||||||
Get the PluginService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
PluginService: The PluginService instance.
|
PluginService: The PluginService instance.
|
||||||
|
|
@ -130,8 +124,7 @@ def get_plugins_service() -> PluginService:
|
||||||
|
|
||||||
|
|
||||||
def get_settings_service() -> SettingsService:
|
def get_settings_service() -> SettingsService:
|
||||||
"""
|
"""Retrieves the SettingsService instance.
|
||||||
Retrieves the SettingsService instance.
|
|
||||||
|
|
||||||
If the service is not yet initialized, it will be initialized before returning.
|
If the service is not yet initialized, it will be initialized before returning.
|
||||||
|
|
||||||
|
|
@ -147,8 +140,7 @@ def get_settings_service() -> SettingsService:
|
||||||
|
|
||||||
|
|
||||||
def get_db_service() -> DatabaseService:
|
def get_db_service() -> DatabaseService:
|
||||||
"""
|
"""Retrieves the DatabaseService instance from the service manager.
|
||||||
Retrieves the DatabaseService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The DatabaseService instance.
|
The DatabaseService instance.
|
||||||
|
|
@ -160,8 +152,7 @@ def get_db_service() -> DatabaseService:
|
||||||
|
|
||||||
|
|
||||||
def get_session() -> Generator[Session, None, None]:
|
def get_session() -> Generator[Session, None, None]:
|
||||||
"""
|
"""Retrieves a session from the database service.
|
||||||
Retrieves a session from the database service.
|
|
||||||
|
|
||||||
Yields:
|
Yields:
|
||||||
Session: A session object.
|
Session: A session object.
|
||||||
|
|
@ -173,8 +164,7 @@ def get_session() -> Generator[Session, None, None]:
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def session_scope() -> Generator[Session, None, None]:
|
def session_scope() -> Generator[Session, None, None]:
|
||||||
"""
|
"""Context manager for managing a session scope.
|
||||||
Context manager for managing a session scope.
|
|
||||||
|
|
||||||
This context manager is used to manage a session scope for database operations.
|
This context manager is used to manage a session scope for database operations.
|
||||||
It ensures that the session is properly committed if no exceptions occur,
|
It ensures that the session is properly committed if no exceptions occur,
|
||||||
|
|
@ -199,8 +189,7 @@ def session_scope() -> Generator[Session, None, None]:
|
||||||
|
|
||||||
|
|
||||||
def get_cache_service() -> CacheService:
|
def get_cache_service() -> CacheService:
|
||||||
"""
|
"""Retrieves the cache service from the service manager.
|
||||||
Retrieves the cache service from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The cache service instance.
|
The cache service instance.
|
||||||
|
|
@ -211,8 +200,7 @@ def get_cache_service() -> CacheService:
|
||||||
|
|
||||||
|
|
||||||
def get_shared_component_cache_service() -> CacheService:
|
def get_shared_component_cache_service() -> CacheService:
|
||||||
"""
|
"""Retrieves the cache service from the service manager.
|
||||||
Retrieves the cache service from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The cache service instance.
|
The cache service instance.
|
||||||
|
|
@ -223,8 +211,7 @@ def get_shared_component_cache_service() -> CacheService:
|
||||||
|
|
||||||
|
|
||||||
def get_session_service() -> SessionService:
|
def get_session_service() -> SessionService:
|
||||||
"""
|
"""Retrieves the session service from the service manager.
|
||||||
Retrieves the session service from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The session service instance.
|
The session service instance.
|
||||||
|
|
@ -235,8 +222,7 @@ def get_session_service() -> SessionService:
|
||||||
|
|
||||||
|
|
||||||
def get_task_service() -> TaskService:
|
def get_task_service() -> TaskService:
|
||||||
"""
|
"""Retrieves the TaskService instance from the service manager.
|
||||||
Retrieves the TaskService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The TaskService instance.
|
The TaskService instance.
|
||||||
|
|
@ -248,8 +234,7 @@ def get_task_service() -> TaskService:
|
||||||
|
|
||||||
|
|
||||||
def get_chat_service() -> ChatService:
|
def get_chat_service() -> ChatService:
|
||||||
"""
|
"""Get the chat service instance.
|
||||||
Get the chat service instance.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ChatService: The chat service instance.
|
ChatService: The chat service instance.
|
||||||
|
|
@ -258,8 +243,7 @@ def get_chat_service() -> ChatService:
|
||||||
|
|
||||||
|
|
||||||
def get_store_service() -> StoreService:
|
def get_store_service() -> StoreService:
|
||||||
"""
|
"""Retrieves the StoreService instance from the service manager.
|
||||||
Retrieves the StoreService instance from the service manager.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
StoreService: The StoreService instance.
|
StoreService: The StoreService instance.
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,7 @@ class NoFactoryRegisteredError(Exception):
|
||||||
|
|
||||||
|
|
||||||
class ServiceManager:
|
class ServiceManager:
|
||||||
"""
|
"""Manages the creation of different services."""
|
||||||
Manages the creation of different services.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.services: dict[str, Service] = {}
|
self.services: dict[str, Service] = {}
|
||||||
|
|
@ -41,18 +39,12 @@ class ServiceManager:
|
||||||
self,
|
self,
|
||||||
service_factory: ServiceFactory,
|
service_factory: ServiceFactory,
|
||||||
):
|
):
|
||||||
"""
|
"""Registers a new factory with dependencies."""
|
||||||
Registers a new factory with dependencies.
|
|
||||||
"""
|
|
||||||
|
|
||||||
service_name = service_factory.service_class.name
|
service_name = service_factory.service_class.name
|
||||||
self.factories[service_name] = service_factory
|
self.factories[service_name] = service_factory
|
||||||
|
|
||||||
def get(self, service_name: ServiceType, default: ServiceFactory | None = None) -> Service:
|
def get(self, service_name: ServiceType, default: ServiceFactory | None = None) -> Service:
|
||||||
"""
|
"""Get (or create) a service by its name."""
|
||||||
Get (or create) a service by its name.
|
|
||||||
"""
|
|
||||||
|
|
||||||
with self.keyed_lock.lock(service_name):
|
with self.keyed_lock.lock(service_name):
|
||||||
if service_name not in self.services:
|
if service_name not in self.services:
|
||||||
self._create_service(service_name, default)
|
self._create_service(service_name, default)
|
||||||
|
|
@ -60,9 +52,7 @@ class ServiceManager:
|
||||||
return self.services[service_name]
|
return self.services[service_name]
|
||||||
|
|
||||||
def _create_service(self, service_name: ServiceType, default: ServiceFactory | None = None):
|
def _create_service(self, service_name: ServiceType, default: ServiceFactory | None = None):
|
||||||
"""
|
"""Create a new service given its name, handling dependencies."""
|
||||||
Create a new service given its name, handling dependencies.
|
|
||||||
"""
|
|
||||||
logger.debug(f"Create service {service_name}")
|
logger.debug(f"Create service {service_name}")
|
||||||
self._validate_service_creation(service_name, default)
|
self._validate_service_creation(service_name, default)
|
||||||
|
|
||||||
|
|
@ -83,26 +73,20 @@ class ServiceManager:
|
||||||
self.services[service_name].set_ready()
|
self.services[service_name].set_ready()
|
||||||
|
|
||||||
def _validate_service_creation(self, service_name: ServiceType, default: ServiceFactory | None = None):
|
def _validate_service_creation(self, service_name: ServiceType, default: ServiceFactory | None = None):
|
||||||
"""
|
"""Validate whether the service can be created."""
|
||||||
Validate whether the service can be created.
|
|
||||||
"""
|
|
||||||
if service_name not in self.factories and default is None:
|
if service_name not in self.factories and default is None:
|
||||||
msg = f"No factory registered for the service class '{service_name.name}'"
|
msg = f"No factory registered for the service class '{service_name.name}'"
|
||||||
raise NoFactoryRegisteredError(msg)
|
raise NoFactoryRegisteredError(msg)
|
||||||
|
|
||||||
def update(self, service_name: ServiceType):
|
def update(self, service_name: ServiceType):
|
||||||
"""
|
"""Update a service by its name."""
|
||||||
Update a service by its name.
|
|
||||||
"""
|
|
||||||
if service_name in self.services:
|
if service_name in self.services:
|
||||||
logger.debug(f"Update service {service_name}")
|
logger.debug(f"Update service {service_name}")
|
||||||
self.services.pop(service_name, None)
|
self.services.pop(service_name, None)
|
||||||
self.get(service_name)
|
self.get(service_name)
|
||||||
|
|
||||||
async def teardown(self):
|
async def teardown(self):
|
||||||
"""
|
"""Teardown all the services."""
|
||||||
Teardown all the services.
|
|
||||||
"""
|
|
||||||
for service in self.services.values():
|
for service in self.services.values():
|
||||||
if service is None:
|
if service is None:
|
||||||
continue
|
continue
|
||||||
|
|
@ -148,18 +132,14 @@ service_manager = ServiceManager()
|
||||||
|
|
||||||
|
|
||||||
def initialize_settings_service():
|
def initialize_settings_service():
|
||||||
"""
|
"""Initialize the settings manager."""
|
||||||
Initialize the settings manager.
|
|
||||||
"""
|
|
||||||
from langflow.services.settings import factory as settings_factory
|
from langflow.services.settings import factory as settings_factory
|
||||||
|
|
||||||
service_manager.register_factory(settings_factory.SettingsServiceFactory())
|
service_manager.register_factory(settings_factory.SettingsServiceFactory())
|
||||||
|
|
||||||
|
|
||||||
def initialize_session_service():
|
def initialize_session_service():
|
||||||
"""
|
"""Initialize the session manager."""
|
||||||
Initialize the session manager.
|
|
||||||
"""
|
|
||||||
from langflow.services.cache import factory as cache_factory
|
from langflow.services.cache import factory as cache_factory
|
||||||
from langflow.services.session import factory as session_service_factory
|
from langflow.services.session import factory as session_service_factory
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,7 @@ from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class ServiceType(str, Enum):
|
class ServiceType(str, Enum):
|
||||||
"""
|
"""Enum for the different types of services that can be registered with the service manager."""
|
||||||
Enum for the different types of services that can be
|
|
||||||
registered with the service manager.
|
|
||||||
"""
|
|
||||||
|
|
||||||
AUTH_SERVICE = "auth_service"
|
AUTH_SERVICE = "auth_service"
|
||||||
CACHE_SERVICE = "cache_service"
|
CACHE_SERVICE = "cache_service"
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,7 @@ BASE_COMPONENTS_PATH = str(Path(__file__).parent.parent.parent / "components")
|
||||||
|
|
||||||
|
|
||||||
def is_list_of_any(field: FieldInfo) -> bool:
|
def is_list_of_any(field: FieldInfo) -> bool:
|
||||||
"""
|
"""Check if the given field is a list or an optional list of any type.
|
||||||
Check if the given field is a list or an optional list of any type.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
field (FieldInfo): The field to be checked.
|
field (FieldInfo): The field to be checked.
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ from langflow.services.cache import ThreadingInMemoryCache
|
||||||
|
|
||||||
|
|
||||||
class SharedComponentCacheService(ThreadingInMemoryCache):
|
class SharedComponentCacheService(ThreadingInMemoryCache):
|
||||||
"""
|
"""A caching service shared across components."""
|
||||||
A caching service shared across components.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name = "shared_component_cache_service"
|
name = "shared_component_cache_service"
|
||||||
|
|
|
||||||
|
|
@ -66,15 +66,11 @@ class SocketIOService(Service):
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_cache(self, sid: str) -> Any:
|
def get_cache(self, sid: str) -> Any:
|
||||||
"""
|
"""Get the cache for a client."""
|
||||||
Get the cache for a client.
|
|
||||||
"""
|
|
||||||
return self.cache_service.get(sid)
|
return self.cache_service.get(sid)
|
||||||
|
|
||||||
def set_cache(self, sid: str, build_result: Any) -> bool:
|
def set_cache(self, sid: str, build_result: Any) -> bool:
|
||||||
"""
|
"""Set the cache for a client."""
|
||||||
Set the cache for a client.
|
|
||||||
"""
|
|
||||||
# client_id is the flow id but that already exists in the cache
|
# client_id is the flow id but that already exists in the cache
|
||||||
# so we need to change it to something else
|
# so we need to change it to something else
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ class LocalStorageService(StorageService):
|
||||||
return str(self.data_dir / flow_id / file_name)
|
return str(self.data_dir / flow_id / file_name)
|
||||||
|
|
||||||
async def save_file(self, flow_id: str, file_name: str, data: bytes):
|
async def save_file(self, flow_id: str, file_name: str, data: bytes):
|
||||||
"""
|
"""Save a file in the local storage.
|
||||||
Save a file in the local storage.
|
|
||||||
|
|
||||||
:param flow_id: The identifier for the flow.
|
:param flow_id: The identifier for the flow.
|
||||||
:param file_name: The name of the file to be saved.
|
:param file_name: The name of the file to be saved.
|
||||||
|
|
@ -46,8 +45,7 @@ class LocalStorageService(StorageService):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
async def get_file(self, flow_id: str, file_name: str) -> bytes:
|
async def get_file(self, flow_id: str, file_name: str) -> bytes:
|
||||||
"""
|
"""Retrieve a file from the local storage.
|
||||||
Retrieve a file from the local storage.
|
|
||||||
|
|
||||||
:param flow_id: The identifier for the flow.
|
:param flow_id: The identifier for the flow.
|
||||||
:param file_name: The name of the file to be retrieved.
|
:param file_name: The name of the file to be retrieved.
|
||||||
|
|
@ -69,8 +67,7 @@ class LocalStorageService(StorageService):
|
||||||
return content
|
return content
|
||||||
|
|
||||||
async def list_files(self, flow_id: str):
|
async def list_files(self, flow_id: str):
|
||||||
"""
|
"""List all files in a specified flow.
|
||||||
List all files in a specified flow.
|
|
||||||
|
|
||||||
:param flow_id: The identifier for the flow.
|
:param flow_id: The identifier for the flow.
|
||||||
:return: A list of file names.
|
:return: A list of file names.
|
||||||
|
|
@ -87,8 +84,7 @@ class LocalStorageService(StorageService):
|
||||||
return files
|
return files
|
||||||
|
|
||||||
async def delete_file(self, flow_id: str, file_name: str):
|
async def delete_file(self, flow_id: str, file_name: str):
|
||||||
"""
|
"""Delete a file from the local storage.
|
||||||
Delete a file from the local storage.
|
|
||||||
|
|
||||||
:param flow_id: The identifier for the flow.
|
:param flow_id: The identifier for the flow.
|
||||||
:param file_name: The name of the file to be deleted.
|
:param file_name: The name of the file to be deleted.
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@ class S3StorageService(StorageService):
|
||||||
self.set_ready()
|
self.set_ready()
|
||||||
|
|
||||||
async def save_file(self, folder: str, file_name: str, data):
|
async def save_file(self, folder: str, file_name: str, data):
|
||||||
"""
|
"""Save a file to the S3 bucket.
|
||||||
Save a file to the S3 bucket.
|
|
||||||
|
|
||||||
:param folder: The folder in the bucket to save the file.
|
:param folder: The folder in the bucket to save the file.
|
||||||
:param file_name: The name of the file to be saved.
|
:param file_name: The name of the file to be saved.
|
||||||
|
|
@ -35,8 +34,7 @@ class S3StorageService(StorageService):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
async def get_file(self, folder: str, file_name: str):
|
async def get_file(self, folder: str, file_name: str):
|
||||||
"""
|
"""Retrieve a file from the S3 bucket.
|
||||||
Retrieve a file from the S3 bucket.
|
|
||||||
|
|
||||||
:param folder: The folder in the bucket where the file is stored.
|
:param folder: The folder in the bucket where the file is stored.
|
||||||
:param file_name: The name of the file to be retrieved.
|
:param file_name: The name of the file to be retrieved.
|
||||||
|
|
@ -52,8 +50,7 @@ class S3StorageService(StorageService):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
async def list_files(self, folder: str):
|
async def list_files(self, folder: str):
|
||||||
"""
|
"""List all files in a specified folder of the S3 bucket.
|
||||||
List all files in a specified folder of the S3 bucket.
|
|
||||||
|
|
||||||
:param folder: The folder in the bucket to list files from.
|
:param folder: The folder in the bucket to list files from.
|
||||||
:return: A list of file names.
|
:return: A list of file names.
|
||||||
|
|
@ -70,8 +67,7 @@ class S3StorageService(StorageService):
|
||||||
return files
|
return files
|
||||||
|
|
||||||
async def delete_file(self, folder: str, file_name: str):
|
async def delete_file(self, folder: str, file_name: str):
|
||||||
"""
|
"""Delete a file from the S3 bucket.
|
||||||
Delete a file from the S3 bucket.
|
|
||||||
|
|
||||||
:param folder: The folder in the bucket where the file is stored.
|
:param folder: The folder in the bucket where the file is stored.
|
||||||
:param file_name: The name of the file to be deleted.
|
:param file_name: The name of the file to be deleted.
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue