Merge branch 'feature/store' of github.com:logspace-ai/langflow into feature/store

This commit is contained in:
cristhianzl 2023-11-16 10:27:23 -03:00
commit 24e9693c53
5 changed files with 28 additions and 36 deletions

View file

@ -1,13 +1,15 @@
import warnings
from typing import Annotated, Any, Dict, List, Optional, Union from typing import Annotated, Any, Dict, List, Optional, Union
from uuid import UUID from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query from fastapi import APIRouter, Depends, HTTPException, Query
from httpx import HTTPStatusError from httpx import HTTPStatusError
from langflow.services.auth import utils as auth_utils from langflow.services.auth import utils as auth_utils
from langflow.services.database.models.user.user import User from langflow.services.database.models.user.user import User
from langflow.services.deps import get_settings_service, get_store_service from langflow.services.deps import get_settings_service, get_store_service
from langflow.services.store.schema import ( from langflow.services.store.schema import (
ComponentResponse, CreateComponentResponse,
DownloadComponentResponse, DownloadComponentResponse,
ListComponentResponse, ListComponentResponse,
ListComponentResponseModel, ListComponentResponseModel,
@ -59,8 +61,8 @@ def check_if_store_has_api_key(
} }
@router.post("/components/", response_model=ComponentResponse, status_code=201) @router.post("/components/", response_model=CreateComponentResponse, status_code=201)
def create_component( async def create_component(
component: StoreComponentCreate, component: StoreComponentCreate,
store_service: StoreService = Depends(get_store_service), store_service: StoreService = Depends(get_store_service),
store_api_Key: str = Depends(get_user_store_api_key), store_api_Key: str = Depends(get_user_store_api_key),
@ -68,6 +70,11 @@ def create_component(
try: try:
# Verify if this is the latest version of Langflow # Verify if this is the latest version of Langflow
# If not, raise an error # 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() langflow_version = get_lf_version_from_pypi()
if langflow_version is None: if langflow_version is None:
raise HTTPException( raise HTTPException(
@ -76,12 +83,14 @@ def create_component(
) )
elif langflow_version != component.last_tested_version: elif langflow_version != component.last_tested_version:
# If the user is using an older version of Langflow, we need to raise an error # 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." 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: except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc)) raise HTTPException(status_code=400, detail=str(exc))

View file

@ -1,4 +1,3 @@
from datetime import datetime
from typing import List, Optional from typing import List, Optional
from uuid import UUID from uuid import UUID
@ -15,24 +14,8 @@ class UsersLikesResponse(BaseModel):
liked_by_user: Optional[bool] liked_by_user: Optional[bool]
class ComponentResponse(BaseModel): class CreateComponentResponse(BaseModel):
id: UUID 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): class TagsIdResponse(BaseModel):
@ -88,6 +71,5 @@ class StoreComponentCreate(BaseModel):
tags: Optional[List[str]] tags: Optional[List[str]]
parent: Optional[UUID] = None parent: Optional[UUID] = None
is_component: Optional[bool] is_component: Optional[bool]
metadata: Optional[dict] last_tested_version: Optional[str] = None
last_tested_version: Optional[str]
public: Optional[bool] = False public: Optional[bool] = False

View file

@ -1,18 +1,19 @@
import json 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 from uuid import UUID
import httpx import httpx
from httpx import HTTPError, HTTPStatusError from httpx import HTTPError, HTTPStatusError
from loguru import logger
from langflow.services.base import Service from langflow.services.base import Service
from langflow.services.store.schema import ( from langflow.services.store.schema import (
ComponentResponse, CreateComponentResponse,
DownloadComponentResponse, DownloadComponentResponse,
ListComponentResponse, ListComponentResponse,
StoreComponentCreate, StoreComponentCreate,
) )
from langflow.services.store.utils import process_tags_for_post from langflow.services.store.utils import process_tags_for_post
from loguru import logger
if TYPE_CHECKING: if TYPE_CHECKING:
from langflow.services.settings.service import SettingsService from langflow.services.settings.service import SettingsService
@ -74,7 +75,7 @@ class StoreService(Service):
async def _get( async def _get(
self, url: str, api_key: Optional[str] = None, params: Optional[Dict[str, Any]] = None 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.""" """Utility method to perform GET requests."""
if api_key: if api_key:
headers = {"Authorization": f"Bearer {api_key}"} headers = {"Authorization": f"Bearer {api_key}"}
@ -257,7 +258,7 @@ class StoreService(Service):
return DownloadComponentResponse(**component) 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}"} headers = {"Authorization": f"Bearer {api_key}"}
component_dict = component_data.dict(exclude_unset=True) component_dict = component_data.dict(exclude_unset=True)
# Parent is a UUID, but the store expects a string # 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 = await client.post(self.components_url, headers=headers, json=component_dict)
response.raise_for_status() response.raise_for_status()
component = response.json()["data"] component = response.json()["data"]
return ComponentResponse(**component) return CreateComponentResponse(**component)
except HTTPError as exc: except HTTPError as exc:
if response: if response:
try: try:

View file

@ -568,7 +568,7 @@ export async function saveFlowStore(
is_component: newFlow.is_component, is_component: newFlow.is_component,
parent: newFlow.parent, parent: newFlow.parent,
tags: tags, tags: tags,
public: publicFlow, status: publicFlow ? "public" : "private",
}); });
if (response.status !== 201) { if (response.status !== 201) {

View file

@ -1,7 +1,7 @@
# FILEPATH: /Users/ogabrielluiz/Projects/langflow2/tests/test_store_service.py # FILEPATH: /Users/ogabrielluiz/Projects/langflow2/tests/test_store_service.py
from datetime import datetime from datetime import datetime
from unittest.mock import patch, Mock from unittest.mock import Mock, patch
from langflow.services.deps import get_store_service 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") @patch("langflow.services.store.service.httpx")
def test_search_components(mock_httpx: Mock, client): def test_search_components(mock_httpx: Mock, client):
# Mock the response from the HTTP GET request # 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 = Mock()
mock_response.json.return_value = { 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 that the search method returns a list of ComponentResponse objects
assert len(components) == 2 assert len(components) == 2
assert all(isinstance(component, ComponentResponse) for component in components) assert all(isinstance(component, CreateComponentResponse) for component in components)