From d664131e6c1732a839f9ae68381665b1dfdd66ca Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Wed, 25 Oct 2023 23:12:23 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20fix(=5F=5Fmain=5F=5F.py):=20add?= =?UTF-8?q?=20'store'=20parameter=20to=20update=5Fsettings=20function=20to?= =?UTF-8?q?=20enable/disable=20store=20feature=20=E2=9C=A8=20feat(=5F=5Fma?= =?UTF-8?q?in=5F=5F.py):=20add=20'store'=20option=20to=20the=20run=20comma?= =?UTF-8?q?nd=20to=20enable/disable=20store=20feature=20=F0=9F=94=A7=20fix?= =?UTF-8?q?(store.py):=20add=20check=5Fif=5Fstore=5Fis=5Fenabled=20endpoin?= =?UTF-8?q?t=20to=20check=20if=20store=20feature=20is=20enabled=20?= =?UTF-8?q?=E2=9C=A8=20feat(store.py):=20add=20get=5Ftags=20endpoint=20to?= =?UTF-8?q?=20retrieve=20tags=20from=20the=20store=20=F0=9F=94=A7=20fix(ba?= =?UTF-8?q?se.py):=20add=20STORE=20setting=20to=20enable/disable=20store?= =?UTF-8?q?=20feature=20=F0=9F=94=A7=20fix(schema.py):=20rename=20'likes?= =?UTF-8?q?=5Fcount'=20field=20to=20'liked=5Fby=5Fcount'=20in=20ComponentR?= =?UTF-8?q?esponse=20and=20ListComponentResponse=20=F0=9F=94=A7=20fix(serv?= =?UTF-8?q?ice.py):=20change=20default=20sorting=20in=20query=5Fcomponents?= =?UTF-8?q?=20function=20to=20sort=20by=20'count(liked=5Fby)'=20=E2=9C=85?= =?UTF-8?q?=20test(test=5Fstore.py):=20update=20sort=20parameter=20in=20te?= =?UTF-8?q?st=5Fsearch=5Fcomponents=20to=20'count(liked=5Fby)'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/__main__.py | 16 +++++----- src/backend/langflow/api/v1/store.py | 30 ++++++++++++++++++- .../langflow/services/settings/base.py | 1 + src/backend/langflow/services/store/schema.py | 10 +++++-- .../langflow/services/store/service.py | 12 ++++++-- tests/test_store.py | 2 +- 6 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/backend/langflow/__main__.py b/src/backend/langflow/__main__.py index f41eaec11..4d3f76498 100644 --- a/src/backend/langflow/__main__.py +++ b/src/backend/langflow/__main__.py @@ -72,6 +72,7 @@ def update_settings( dev: bool = False, remove_api_keys: bool = False, components_path: Optional[Path] = None, + store: bool = True, ): """Update the settings from a config file.""" @@ -90,6 +91,9 @@ def update_settings( if components_path: logger.debug(f"Adding component path {components_path}") settings_service.settings.update_settings(COMPONENTS_PATH=components_path) + if not store: + logger.debug("Setting store to False") + settings_service.settings.update_settings(STORE=False) @app.command() @@ -126,13 +130,6 @@ def run( default=None, ), dev: bool = typer.Option(False, help="Run in development mode (may contain bugs)"), - # This variable does not work but is set by the .env file - # and works with Pydantic - # database_url: str = typer.Option( - # None, - # help="Database URL to connect to. If not provided, a local SQLite database will be used.", - # envvar="LANGFLOW_DATABASE_URL", - # ), path: str = typer.Option( None, help="Path to the frontend directory containing build files. This is for development purposes only.", @@ -153,6 +150,11 @@ def run( help="Run only the backend server without the frontend.", envvar="LANGFLOW_BACKEND_ONLY", ), + store: bool = typer.Option( + True, + help="Enables the store features.", + envvar="LANGFLOW_STORE", + ), ): """ Run the Langflow. diff --git a/src/backend/langflow/api/v1/store.py b/src/backend/langflow/api/v1/store.py index 59a88153d..bbd05f4aa 100644 --- a/src/backend/langflow/api/v1/store.py +++ b/src/backend/langflow/api/v1/store.py @@ -11,6 +11,7 @@ from langflow.services.store.schema import ( DownloadComponentResponse, ListComponentResponse, StoreComponentCreate, + TagResponse, ) from fastapi import APIRouter, Depends, HTTPException, Query @@ -44,6 +45,13 @@ def get_optional_user_store_api_key( return decrypted +@router.get("/") +def check_if_store_is_enabled( + settings_service=Depends(get_settings_service), +): + return {"enabled": settings_service.settings.STORE} + + @router.post("/components/", response_model=ComponentResponse, status_code=201) def create_component( component: StoreComponentCreate, @@ -65,7 +73,16 @@ def list_components( store_api_Key: str = Depends(get_optional_user_store_api_key), ): try: - fields = ["id", "name", "description", "user_created.name", "is_component"] + fields = [ + "id", + "name", + "description", + "user_created.name", + "is_component", + "tags.tags_id.name", + "tags.tags_id.id", + "count(liked_by)", + ] result = store_service.query_components( store_api_Key, page, @@ -143,3 +160,14 @@ async def search_endpoint( ) except Exception as exc: raise HTTPException(status_code=500, detail=str(exc)) + + +@router.get("/tags", response_model=List[TagResponse]) +def get_tags( + store_service: StoreService = Depends(get_store_service), + store_api_Key: str = Depends(get_optional_user_store_api_key), +): + try: + return store_service.get_tags(store_api_Key) + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) diff --git a/src/backend/langflow/services/settings/base.py b/src/backend/langflow/services/settings/base.py index c666f48ce..294f5881a 100644 --- a/src/backend/langflow/services/settings/base.py +++ b/src/backend/langflow/services/settings/base.py @@ -52,6 +52,7 @@ class Settings(BaseSettings): LANGFUSE_PUBLIC_KEY: Optional[str] = None LANGFUSE_HOST: Optional[str] = None + STORE: Optional[bool] = True STORE_URL: Optional[str] = None DOWNLOAD_WEBHOOK_URL: Optional[str] = None diff --git a/src/backend/langflow/services/store/schema.py b/src/backend/langflow/services/store/schema.py index 34a0ac574..259d341b2 100644 --- a/src/backend/langflow/services/store/schema.py +++ b/src/backend/langflow/services/store/schema.py @@ -4,6 +4,11 @@ from typing import Optional, List from uuid import UUID +class TagResponse(BaseModel): + id: UUID + name: Optional[str] + + class ComponentResponse(BaseModel): id: UUID status: Optional[str] @@ -17,16 +22,15 @@ class ComponentResponse(BaseModel): description: Optional[str] data: Optional[dict] tags: Optional[List[int]] - likes_count: Optional[List[UUID]] + liked_by_count: Optional[List[UUID]] parent: Optional[UUID] class ListComponentResponse(BaseModel): - (["id", "name", "description", "count(likes)", "is_component"]) id: UUID name: Optional[str] description: Optional[str] - likes_count: Optional[int] + liked_by_count: Optional[int] is_component: Optional[bool] diff --git a/src/backend/langflow/services/store/service.py b/src/backend/langflow/services/store/service.py index 06d3deea9..83a199445 100644 --- a/src/backend/langflow/services/store/service.py +++ b/src/backend/langflow/services/store/service.py @@ -70,7 +70,7 @@ class StoreService(Service): tags: Optional[List[str]] = None, date_from: Optional[datetime] = None, date_to: Optional[datetime] = None, - sort: Optional[List[str]] = ["-likes"], + sort: Optional[List[str]] = ["-count(liked_by)"], fields: Optional[List[str]] = None, filter_by_user: bool = False, ) -> List[ComponentResponse]: @@ -151,7 +151,9 @@ class StoreService(Service): params["fields"] = ( ",".join(fields) if fields - else ",".join(["id", "name", "description", "count(likes)", "is_component"]) + else ",".join( + ["id", "name", "description", "count(liked_by)", "is_component"] + ) ) # Only public components or the ones created by the user # check for "public" or "Public" @@ -208,3 +210,9 @@ class StoreService(Service): except UnboundLocalError: pass raise ValueError(f"Upload failed: {exc}") + + def get_tags(self, api_key: str) -> List[Dict[str, Any]]: + url = f"{self.base_url}/items/tags" + params = {"fields": ",".join(["id", "name"])} + tags = self._get(url, api_key, params) + return tags diff --git a/tests/test_store.py b/tests/test_store.py index 706100fe6..c4fbcca7e 100644 --- a/tests/test_store.py +++ b/tests/test_store.py @@ -48,7 +48,7 @@ def test_search_components(mock_httpx: Mock, client): "filter[name][_like]": "test", "page": 1, "limit": 5, - "sort": "likes", + "sort": "count(liked_by)", }, )