Merge branch 'zustand/io/migration' of github.com:logspace-ai/langflow into zustand/io/migration

This commit is contained in:
igorrCarvalho 2024-03-11 17:34:14 -03:00
commit 0484a193b1
8 changed files with 72 additions and 62 deletions

View file

@ -8,7 +8,7 @@ from sqlmodel import Session, select
from langflow.api.utils import update_frontend_node_with_template_values
from langflow.api.v1.schemas import (
CustomComponentCode,
CustomComponentRequest,
InputValueRequest,
ProcessResponse,
RunResponse,
@ -253,12 +253,12 @@ def get_version():
@router.post("/custom_component", status_code=HTTPStatus.OK)
async def custom_component(
raw_code: CustomComponentCode,
raw_code: CustomComponentRequest,
user: User = Depends(get_current_active_user),
):
component = CustomComponent(code=raw_code.code)
built_frontend_node = build_custom_component_template(component, user_id=user.id)
built_frontend_node, _ = build_custom_component_template(component, user_id=user.id)
built_frontend_node = update_frontend_node_with_template_values(built_frontend_node, raw_code.frontend_node)
return built_frontend_node
@ -275,23 +275,40 @@ async def reload_custom_component(path: str, user: User = Depends(get_current_ac
raise ValueError(content)
extractor = CustomComponent(code=content)
return build_custom_component_template(extractor, user_id=user.id)
frontend_node, _ = build_custom_component_template(extractor, user_id=user.id)
return frontend_node
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc))
@router.post("/custom_component/update", status_code=HTTPStatus.OK)
async def custom_component_update(
raw_code: CustomComponentCode,
code_request: CustomComponentRequest,
user: User = Depends(get_current_active_user),
):
component = CustomComponent(code=raw_code.code)
"""
Update a custom component with the provided code request.
component_node = build_custom_component_template(
This endpoint generates the CustomComponentFrontendNode normally but then runs the `update_build_config` method
on the latest version of the template. This ensures that every time it runs, it has the latest version of the template.
Args:
code_request (CustomComponentRequest): The code request containing the updated code for the custom component.
user (User, optional): The user making the request. Defaults to the current active user.
Returns:
dict: The updated custom component node.
"""
component = CustomComponent(code=code_request.code)
component_node, cc_instance = build_custom_component_template(
component,
user_id=user.id,
update_field=raw_code.field,
update_field_value=raw_code.field_value,
)
# Update the field
updated_build_config = cc_instance.update_build_config(
code_request.template, code_request.field_value, code_request.field_name
)
component_node["template"] = updated_build_config
return component_node

View file

@ -4,8 +4,17 @@ from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from uuid import UUID
from pydantic import BaseModel, Field, RootModel, field_validator, model_serializer
from pydantic import (
BaseModel,
ConfigDict,
Field,
RootModel,
field_serializer,
field_validator,
model_serializer,
)
from langflow.schema import dotdict
from langflow.services.database.models.api_key.model import ApiKeyRead
from langflow.services.database.models.base import orjson_dumps
from langflow.services.database.models.flow import FlowCreate, FlowRead
@ -161,12 +170,18 @@ class StreamData(BaseModel):
return f"event: {self.event}\ndata: {orjson_dumps(self.data, indent_2=False)}\n\n"
class CustomComponentCode(BaseModel):
class CustomComponentRequest(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
code: str
field: Optional[str] = None
field_value: Optional[Any] = None
template: Optional[dict] = None
frontend_node: Optional[dict] = None
@field_serializer("template")
def template_into_dotdict(v):
return dotdict(v)
class CustomComponentResponseError(BaseModel):
detail: str

View file

@ -162,14 +162,16 @@ class Graph:
if vertex is None:
raise ValueError(f"Vertex {vertex_id} not found")
vertex.update_raw_params({"session_id": session_id})
# Process the graph
try:
await self.process()
self.increment_run_count()
except Exception as exc:
logger.exception(exc)
raise ValueError(f"Error running graph: {exc}") from exc
# Get the outputs
vertex_outputs = []
for vertex_id in self._is_output_vertices:
for vertex_id in self.vertices:
vertex = self.get_vertex(vertex_id)
if vertex is None:
raise ValueError(f"Vertex {vertex_id} not found")
@ -178,6 +180,7 @@ class Graph:
await vertex.consume_async_generator()
if not outputs or (vertex.display_name in outputs or vertex.id in outputs):
vertex_outputs.append(vertex.result)
return vertex_outputs
async def run(

View file

@ -3,7 +3,7 @@ import contextlib
import re
import traceback
import warnings
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Optional, Tuple, Union
from uuid import UUID
from fastapi import HTTPException
@ -243,9 +243,7 @@ def get_field_dict(field: Union[TemplateField, dict]):
def run_build_config(
custom_component: CustomComponent,
user_id: Optional[Union[str, UUID]] = None,
update_field=None,
update_field_value=None,
):
) -> Tuple[dict, CustomComponent]:
"""Build the field configuration for a custom component"""
try:
@ -274,38 +272,6 @@ def run_build_config(
# as a dict with the same keys as TemplateField
field_dict = get_field_dict(field)
build_config[field_name] = field_dict
# This has to be done to set refresh if options or value are callable
if update_field is not None and field_name != update_field:
build_config = update_field_dict(
custom_component_instance=custom_instance,
field_dict=field_dict,
build_config=build_config,
call=False,
)
continue
try:
build_config = update_field_dict(
custom_component_instance=custom_instance,
field_dict=field_dict,
build_config=build_config,
update_field=update_field,
update_field_value=update_field_value,
call=True,
)
build_config[field_name] = field_dict
except Exception as exc:
logger.error(f"Error while getting build_config: {str(exc)}")
if isinstance(exc, UpdateBuildConfigError):
message = str(exc)
else:
message = f"Error while getting build_config: {str(exc)}"
raise HTTPException(
status_code=400,
detail={
"error": message,
"traceback": traceback.format_exc(),
},
) from exc
return build_config, custom_instance
@ -358,9 +324,7 @@ def add_code_field(frontend_node: CustomComponentFrontendNode, raw_code, field_c
def build_custom_component_template(
custom_component: CustomComponent,
user_id: Optional[Union[str, UUID]] = None,
update_field: Optional[str] = None,
update_field_value: Optional[str] = None,
) -> Optional[Dict[str, Any]]:
) -> Tuple[Dict[str, Any], CustomComponent]:
"""Build a custom component template for the langchain"""
try:
frontend_node = build_frontend_node(custom_component.template_config)
@ -368,8 +332,6 @@ def build_custom_component_template(
field_config, custom_instance = run_build_config(
custom_component,
user_id=user_id,
update_field=update_field,
update_field_value=update_field_value,
)
entrypoint_args = custom_component.get_function_entrypoint_args
@ -383,7 +345,7 @@ def build_custom_component_template(
reorder_fields(frontend_node, custom_instance._get_field_order())
return frontend_node.to_dict(add_name=False)
return frontend_node.to_dict(add_name=False), custom_instance
except Exception as exc:
if isinstance(exc, HTTPException):
raise exc
@ -403,7 +365,7 @@ def create_component_template(component):
component_extractor = CustomComponent(code=component_code)
component_template = build_custom_component_template(component_extractor)
component_template, _ = build_custom_component_template(component_extractor)
if not component_template["output_types"] and component_output_types:
component_template["output_types"] = component_output_types

View file

@ -85,8 +85,8 @@ export default function GenericNode({
// return
if (!thisNodeTemplate.code) return;
const currentCode = thisNodeTemplate.code.value;
const thisNodesCode = data.node!.template.code.value;
const currentCode = thisNodeTemplate.code?.value;
const thisNodesCode = data.node!.template?.code?.value;
if (currentCode !== thisNodesCode) {
addToOutdatedNodes(data.id);
setIsOutdated(true);
@ -96,7 +96,7 @@ export default function GenericNode({
setIsOutdated(false);
}
// template.code can be undefined
}, [data.node?.template.code.value]);
}, [data.node?.template?.code?.value]);
const updateNodeCode = useCallback(
(newNodeClass: APIClassType, code: string, name: string) => {

View file

@ -4,6 +4,7 @@ import { BASE_URL_API } from "../../constants/constants";
import { api } from "../../controllers/API/api";
import {
APIObjectType,
APITemplateType,
Component,
LoginType,
Users,
@ -369,11 +370,13 @@ export async function postCustomComponent(
export async function postCustomComponentUpdate(
code: string,
template: APITemplateType,
field: string,
field_value: any
): Promise<AxiosResponse<APIClassType>> {
return await api.post(`${BASE_URL_API}custom_component/update`, {
code,
template,
field,
field_value,
});

View file

@ -9,9 +9,15 @@ export const handleUpdateValues = async (name: string, data: NodeDataType) => {
console.error("Code not found in the template");
return;
}
const template = data.node?.template;
if (!template) {
console.error("No template found in the node.");
return;
}
try {
let newTemplate = await postCustomComponentUpdate(
code,
template,
name,
data.node?.template[name]?.value
)

View file

@ -24,7 +24,9 @@ def test_document_to_record_component():
# Act
# Replace with your actual test data
document = Document(page_content="key: value", metadata={"url": "https://example.com"})
document = Document(
page_content="key: value", metadata={"url": "https://example.com"}
)
result = document_to_record_component.build(document)
# Assert
@ -37,12 +39,14 @@ def test_uuid_generator_component():
uuid_generator_component = helpers.UUIDGeneratorComponent()
uuid_generator_component.code = open(helpers.IDGenerator.__file__, "r").read()
frontend_node = build_custom_component_template(uuid_generator_component)
frontend_node, _ = build_custom_component_template(uuid_generator_component)
# Act
build_config = frontend_node.get("template")
field_name = "unique_id"
build_config = uuid_generator_component.update_build_config(build_config, None, field_name)
build_config = uuid_generator_component.update_build_config(
build_config, None, field_name
)
unique_id = build_config["unique_id"]["value"]
result = uuid_generator_component.build(unique_id)