From 7b5066e6b1d43765bb2244359312e0643cb89e6a Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Fri, 1 Dec 2023 22:06:46 -0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(store.py):=20add=20PATCH=20end?= =?UTF-8?q?point=20to=20update=20a=20component=20in=20the=20store=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(service.py):=20add=20update=20method=20to=20?= =?UTF-8?q?StoreService=20class=20to=20handle=20PATCH=20requests=20for=20u?= =?UTF-8?q?pdating=20a=20component=20in=20the=20store?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/store.py | 34 +++++++++++++++++++ .../langflow/services/store/service.py | 33 ++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/backend/langflow/api/v1/store.py b/src/backend/langflow/api/v1/store.py index e3d6cee9d..b481cbf2a 100644 --- a/src/backend/langflow/api/v1/store.py +++ b/src/backend/langflow/api/v1/store.py @@ -66,6 +66,7 @@ async def check_if_store_has_api_key( return {"has_api_key": api_key is not None, "is_valid": is_valid} + @router.post("/components/", response_model=CreateComponentResponse, status_code=201) async def share_component( component: StoreComponentCreate, @@ -99,6 +100,39 @@ async def share_component( except Exception as exc: raise HTTPException(status_code=400, detail=str(exc)) +@router.patch("/components/{component_id}", response_model=CreateComponentResponse, status_code=201) +async def update_component( + component_id: UUID, + component: StoreComponentCreate, + store_service: StoreService = Depends(get_store_service), + store_api_Key: str = Depends(get_user_store_api_key), +): + try: + # Verify if this is the latest version of Langflow + # If not, raise an error + if not component.last_tested_version: + # Get the local version of Langflow + from langflow import __version__ as current_version + + component.last_tested_version = current_version + langflow_version = get_lf_version_from_pypi() + if langflow_version is None: + raise HTTPException( + status_code=500, + detail="Unable to verify the latest version of Langflow", + ) + elif langflow_version != component.last_tested_version: + # If the user is using an older version of Langflow, we need to raise an error + # raise ValueError( + warnings.warn( + f"Your version of Langflow ({component.last_tested_version}) is outdated." + f" Please update to the latest version ({langflow_version}) and try again." + ) + + result = await store_service.update(store_api_Key, component_id, component) + return result + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) @router.get("/components/", response_model=ListComponentResponseModel) async def get_components( diff --git a/src/backend/langflow/services/store/service.py b/src/backend/langflow/services/store/service.py index acd931d34..0f466cc20 100644 --- a/src/backend/langflow/services/store/service.py +++ b/src/backend/langflow/services/store/service.py @@ -350,6 +350,39 @@ class StoreService(Service): pass raise ValueError(f"Upload failed: {exc}") + async def update(self, api_key: str, component_id: UUID, component_data: StoreComponentCreate) -> CreateComponentResponse: + # Patch is the same as post, but we need to add the id to the url + headers = {"Authorization": f"Bearer {api_key}"} + component_dict = component_data.model_dump(exclude_unset=True) + # Parent is a UUID, but the store expects a string + response = None + if component_dict.get("parent"): + component_dict["parent"] = str(component_dict["parent"]) + + component_dict = process_tags_for_post(component_dict) + try: + # response = httpx.post(self.components_url, headers=headers, json=component_dict) + # response.raise_for_status() + async with httpx.AsyncClient() as client: + response = await client.patch(self.components_url + f"/{component_id}", + headers=headers, json=component_dict) + response.raise_for_status() + component = response.json()["data"] + return CreateComponentResponse(**component) + except HTTPError as exc: + if response: + try: + errors = response.json() + message = errors["errors"][0]["message"] + if message == "An unexpected error occurred.": + # This is a bug in Directus that returns this error + # when an error was thrown in the flow + message = "You already have a component with this name. Please choose a different name." + raise FilterError(message) + except UnboundLocalError: + pass + raise ValueError(f"Upload failed: {exc}") + async def get_tags(self) -> List[Dict[str, Any]]: url = f"{self.base_url}/items/tags" params = {"fields": ",".join(["id", "name"])}