From e925da56716ad05dc63df7b2db92fc5d178e876e Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 16 Nov 2023 09:44:07 -0300 Subject: [PATCH 1/4] Add last tested version to component creation and handle outdated versions --- src/backend/langflow/api/v1/store.py | 21 +++++++++++++----- src/backend/langflow/services/store/schema.py | 22 ++----------------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/backend/langflow/api/v1/store.py b/src/backend/langflow/api/v1/store.py index bfb739c1c..4bf7fa2ed 100644 --- a/src/backend/langflow/api/v1/store.py +++ b/src/backend/langflow/api/v1/store.py @@ -1,13 +1,15 @@ +import warnings from typing import Annotated, Any, Dict, List, Optional, Union from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query from httpx import HTTPStatusError + from langflow.services.auth import utils as auth_utils from langflow.services.database.models.user.user import User from langflow.services.deps import get_settings_service, get_store_service from langflow.services.store.schema import ( - ComponentResponse, + CreateComponentResponse, DownloadComponentResponse, ListComponentResponse, ListComponentResponseModel, @@ -59,8 +61,8 @@ def check_if_store_has_api_key( } -@router.post("/components/", response_model=ComponentResponse, status_code=201) -def create_component( +@router.post("/components/", response_model=CreateComponentResponse, status_code=201) +async def create_component( component: StoreComponentCreate, store_service: StoreService = Depends(get_store_service), store_api_Key: str = Depends(get_user_store_api_key), @@ -68,6 +70,11 @@ def create_component( 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( @@ -76,12 +83,14 @@ def create_component( ) 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( + # raise ValueError( + warnings.warn( f"Your version of Langflow ({component.last_tested_version}) is outdated." - " Please update to the latest version ({langflow_version}) and try again." + f" Please update to the latest version ({langflow_version}) and try again." ) - return store_service.upload(store_api_Key, component) + result = await store_service.upload(store_api_Key, component) + return result except Exception as exc: raise HTTPException(status_code=400, detail=str(exc)) diff --git a/src/backend/langflow/services/store/schema.py b/src/backend/langflow/services/store/schema.py index 51a203d18..cbd9b3a52 100644 --- a/src/backend/langflow/services/store/schema.py +++ b/src/backend/langflow/services/store/schema.py @@ -1,4 +1,3 @@ -from datetime import datetime from typing import List, Optional from uuid import UUID @@ -15,24 +14,8 @@ class UsersLikesResponse(BaseModel): liked_by_user: Optional[bool] -class ComponentResponse(BaseModel): +class CreateComponentResponse(BaseModel): id: UUID - status: Optional[str] - sort: Optional[int] - user_name: Optional[str] - date_created: Optional[datetime] - user_updated: Optional[UUID] - date_updated: Optional[datetime] - is_component: Optional[bool] - name: Optional[str] - description: Optional[str] - data: Optional[dict] - tags: Optional[List[int]] - liked_by_count: Optional[int] - downloads_count: Optional[int] - parent: Optional[UUID] = None - metadata: Optional[dict] - last_tested_version: Optional[str] class TagsIdResponse(BaseModel): @@ -88,6 +71,5 @@ class StoreComponentCreate(BaseModel): tags: Optional[List[str]] parent: Optional[UUID] = None is_component: Optional[bool] - metadata: Optional[dict] - last_tested_version: Optional[str] + last_tested_version: Optional[str] = None public: Optional[bool] = False From 8f23c29818daacfc1be8e41aadb5588dcf70c64d Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 16 Nov 2023 09:44:17 -0300 Subject: [PATCH 2/4] Refactor StoreService upload method to return CreateComponentResponse --- src/backend/langflow/services/store/service.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/backend/langflow/services/store/service.py b/src/backend/langflow/services/store/service.py index 6833d84ed..9257f0a21 100644 --- a/src/backend/langflow/services/store/service.py +++ b/src/backend/langflow/services/store/service.py @@ -1,18 +1,19 @@ import json -from typing import TYPE_CHECKING, Any, Dict, List, Optional +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union from uuid import UUID import httpx from httpx import HTTPError, HTTPStatusError +from loguru import logger + from langflow.services.base import Service from langflow.services.store.schema import ( - ComponentResponse, + CreateComponentResponse, DownloadComponentResponse, ListComponentResponse, StoreComponentCreate, ) from langflow.services.store.utils import process_tags_for_post -from loguru import logger if TYPE_CHECKING: from langflow.services.settings.service import SettingsService @@ -74,7 +75,7 @@ class StoreService(Service): async def _get( self, url: str, api_key: Optional[str] = None, params: Optional[Dict[str, Any]] = None - ) -> List[Dict[str, Any]]: + ) -> Union[List[Dict[str, Any]], Dict[str, Any]]: """Utility method to perform GET requests.""" if api_key: headers = {"Authorization": f"Bearer {api_key}"} @@ -257,7 +258,7 @@ class StoreService(Service): return DownloadComponentResponse(**component) - async def upload(self, api_key: str, component_data: StoreComponentCreate) -> ComponentResponse: + async def upload(self, api_key: str, component_data: StoreComponentCreate) -> CreateComponentResponse: headers = {"Authorization": f"Bearer {api_key}"} component_dict = component_data.dict(exclude_unset=True) # Parent is a UUID, but the store expects a string @@ -273,7 +274,7 @@ class StoreService(Service): response = await client.post(self.components_url, headers=headers, json=component_dict) response.raise_for_status() component = response.json()["data"] - return ComponentResponse(**component) + return CreateComponentResponse(**component) except HTTPError as exc: if response: try: From 0f7c4861f4c1630f9213bd0824ae4135d8682d59 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 16 Nov 2023 09:44:21 -0300 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=90=9B=20fix(API/index.ts):=20change?= =?UTF-8?q?=20'public'=20property=20to=20'status'=20and=20set=20it=20to=20?= =?UTF-8?q?"public"=20or=20"private"=20based=20on=20the=20value=20of=20pub?= =?UTF-8?q?licFlow=20to=20improve=20clarity=20and=20consistency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/controllers/API/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 73450468e..2e47fe522 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -568,7 +568,7 @@ export async function saveFlowStore( is_component: newFlow.is_component, parent: newFlow.parent, tags: tags, - public: publicFlow, + status: publicFlow ? "public" : "private", }); if (response.status !== 201) { From 883bf3a86a309d72ae8ddfe33c375268d77faab4 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 16 Nov 2023 09:44:35 -0300 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=94=A7=20fix(test=5Fstore.py):=20fix?= =?UTF-8?q?=20import=20statement=20for=20CreateComponentResponse=20in=20te?= =?UTF-8?q?st=5Fsearch=5Fcomponents=20function=20=F0=9F=9A=80=20feat(test?= =?UTF-8?q?=5Fstore.py):=20update=20import=20statement=20for=20CreateCompo?= =?UTF-8?q?nentResponse=20in=20test=5Fsearch=5Fcomponents=20function=20to?= =?UTF-8?q?=20reflect=20changes=20in=20schema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_store.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_store.py b/tests/test_store.py index c4fbcca7e..d139537fa 100644 --- a/tests/test_store.py +++ b/tests/test_store.py @@ -1,7 +1,7 @@ # FILEPATH: /Users/ogabrielluiz/Projects/langflow2/tests/test_store_service.py from datetime import datetime -from unittest.mock import patch, Mock +from unittest.mock import Mock, patch from langflow.services.deps import get_store_service @@ -9,7 +9,7 @@ from langflow.services.deps import get_store_service @patch("langflow.services.store.service.httpx") def test_search_components(mock_httpx: Mock, client): # Mock the response from the HTTP GET request - from langflow.services.store.schema import ComponentResponse + from langflow.services.store.schema import CreateComponentResponse mock_response = Mock() mock_response.json.return_value = { @@ -54,4 +54,4 @@ def test_search_components(mock_httpx: Mock, client): # Assert that the search method returns a list of ComponentResponse objects assert len(components) == 2 - assert all(isinstance(component, ComponentResponse) for component in components) + assert all(isinstance(component, CreateComponentResponse) for component in components)