From 8ea2a825a8d0af2ec4b9eb43b8f786bc6b008504 Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Tue, 30 May 2023 21:25:30 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20feat(api):=20add=20tags=20to=20r?= =?UTF-8?q?outers=20for=20better=20organization=20This=20commit=20adds=20t?= =?UTF-8?q?ags=20to=20the=20routers=20in=20the=20API=20to=20improve=20orga?= =?UTF-8?q?nization=20and=20make=20it=20easier=20to=20find=20specific=20en?= =?UTF-8?q?dpoints.=20The=20Chat=20router=20now=20has=20a=20"Chat"=20tag,?= =?UTF-8?q?=20the=20Flows=20router=20has=20a=20"Flows"=20tag,=20the=20Vali?= =?UTF-8?q?date=20router=20has=20a=20"Validate"=20tag,=20and=20the=20Base?= =?UTF-8?q?=20router=20has=20a=20"Base"=20tag.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐛 fix(api): fix typo in Validate router prefix This commit fixes a typo in the Validate router prefix. The prefix was misspelled as "validate" instead of "Validate". ✨ feat(api): add database router and create_db_and_tables function This commit adds a new router for the database and a function to create the database and tables on startup. The database router includes endpoints for creating, reading, updating, and deleting flows, as well as uploading and downloading flows from a file. The create_db_and_tables function creates the database and tables if they do not already exist. 🐛 fix(api): fix logger import in main.py This commit fixes an import error in main.py where the logger was being imported from the wrong module. The logger is now imported from langflow.utils.logger. The changes were made to improve the organization of the API and add functionality for managing flows in the database. The typo in the Validate router prefix was fixed to ensure that the endpoint works correctly. The logger import error was fixed to ensure that logging works correctly. --- src/backend/langflow/api/chat.py | 2 +- src/backend/langflow/api/database.py | 103 ++++++++++++++++++++++++++ src/backend/langflow/api/endpoints.py | 16 +++- src/backend/langflow/api/schemas.py | 5 ++ src/backend/langflow/api/validate.py | 2 +- src/backend/langflow/main.py | 12 +++ 6 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 src/backend/langflow/api/database.py diff --git a/src/backend/langflow/api/chat.py b/src/backend/langflow/api/chat.py index 4afa6c22f..9de93abf0 100644 --- a/src/backend/langflow/api/chat.py +++ b/src/backend/langflow/api/chat.py @@ -9,7 +9,7 @@ from fastapi import ( from langflow.api.chat_manager import ChatManager from langflow.utils.logger import logger -router = APIRouter() +router = APIRouter(tags=["Chat"]) chat_manager = ChatManager() diff --git a/src/backend/langflow/api/database.py b/src/backend/langflow/api/database.py new file mode 100644 index 000000000..f6e5cae47 --- /dev/null +++ b/src/backend/langflow/api/database.py @@ -0,0 +1,103 @@ +from typing import List +from uuid import UUID +from langflow.api.schemas import FlowListCreate +from langflow.database.models.flow import Flow, FlowCreate, FlowRead +from langflow.database.base import get_session +from sqlmodel import Session, select +from fastapi import APIRouter, Depends, HTTPException + + +from fastapi import File, UploadFile +import json + +# build router +router = APIRouter(prefix="/flows", tags=["Flows"]) + + +@router.post("/", response_model=FlowRead) +def create_flow(*, session: Session = Depends(get_session), flow: FlowCreate): + """Create a new flow.""" + db_flow = Flow.from_orm(flow) + session.add(db_flow) + session.commit() + session.refresh(db_flow) + return db_flow + + +@router.get("/", response_model=list[FlowRead]) +def read_flows(*, session: Session = Depends(get_session)): + """Read all flows.""" + flows = session.exec(select(Flow)).all() + return flows + + +@router.get("/{flow_id}", response_model=FlowRead) +def read_flow(*, session: Session = Depends(get_session), flow_id: UUID): + """Read a flow.""" + flow = session.get(Flow, flow_id) + if not flow: + raise HTTPException(status_code=404, detail="Flow not found") + return flow + + +@router.put("/{flow_id}", response_model=FlowRead) +def update_flow( + *, session: Session = Depends(get_session), flow_id: UUID, flow: FlowCreate +): + """Update a flow.""" + db_flow = session.get(Flow, flow_id) + if not db_flow: + raise HTTPException(status_code=404, detail="Flow not found") + update_data = flow.dict(exclude_unset=True) + for key, value in update_data.items(): + setattr(db_flow, key, value) + session.add(db_flow) + session.commit() + session.refresh(db_flow) + return db_flow + + +@router.delete("/{flow_id}") +def delete_flow(*, session: Session = Depends(get_session), flow_id: UUID): + """Delete a flow.""" + flow = session.get(Flow, flow_id) + if not flow: + raise HTTPException(status_code=404, detail="Flow not found") + session.delete(flow) + session.commit() + return {"message": "Flow deleted successfully"} + + +# Define a new model to handle multiple flows + + +@router.post("/batch/", response_model=List[FlowRead]) +def create_flows(*, session: Session = Depends(get_session), flow_list: FlowListCreate): + """Create multiple new flows.""" + db_flows = [] + for flow in flow_list.flows: + db_flow = Flow.from_orm(flow) + session.add(db_flow) + db_flows.append(db_flow) + session.commit() + for db_flow in db_flows: + session.refresh(db_flow) + return db_flows + + +@router.post("/upload/", response_model=List[FlowRead]) +async def upload_file( + *, session: Session = Depends(get_session), file: UploadFile = File(...) +): + """Upload flows from a file.""" + contents = await file.read() + data = json.loads(contents) + flow_list = FlowListCreate(**data) + return create_flows(session=session, flow_list=flow_list) + + +@router.get("/download/") +async def download_file(*, session: Session = Depends(get_session)): + """Download all flows as a file.""" + flows = read_flows(session=session) + return {"file": json.dumps([flow.dict() for flow in flows])} diff --git a/src/backend/langflow/api/endpoints.py b/src/backend/langflow/api/endpoints.py index 021a81ca8..dacdad64b 100644 --- a/src/backend/langflow/api/endpoints.py +++ b/src/backend/langflow/api/endpoints.py @@ -1,7 +1,7 @@ -import logging +from langflow.utils.logger import logger from importlib.metadata import version -from fastapi import APIRouter, HTTPException +from fastapi import APIRouter, File, HTTPException, UploadFile from langflow.api.schemas import ( ExportedFlow, @@ -11,10 +11,10 @@ from langflow.api.schemas import ( ) from langflow.interface.run import process_graph_cached from langflow.interface.types import build_langchain_types_dict +from langflow.cache import cache_manager # build router -router = APIRouter() -logger = logging.getLogger(__name__) +router = APIRouter(tags=["Base"]) @router.get("/all") @@ -45,3 +45,11 @@ def get_version(): @router.get("/health") def get_health(): return {"status": "OK"} + + +# Make an endpoint to upload a file using the client_id and +# cache the file in the backend +@router.post("/uploadfile/{client_id}") +async def create_upload_file(client_id: str, file: UploadFile = File(...)): + + # TODO: Implement this endpoint diff --git a/src/backend/langflow/api/schemas.py b/src/backend/langflow/api/schemas.py index f73b0642d..a9cb4dcb6 100644 --- a/src/backend/langflow/api/schemas.py +++ b/src/backend/langflow/api/schemas.py @@ -1,4 +1,5 @@ from typing import Any, Dict, List, Union +from langflow.database.models.flow import FlowCreate from pydantic import BaseModel, validator @@ -68,3 +69,7 @@ class FileResponse(ChatMessage): if v not in ["image", "csv"]: raise ValueError("data_type must be image or csv") return v + + +class FlowListCreate(BaseModel): + flows: List[FlowCreate] diff --git a/src/backend/langflow/api/validate.py b/src/backend/langflow/api/validate.py index 0e2a7752c..fade4bdf8 100644 --- a/src/backend/langflow/api/validate.py +++ b/src/backend/langflow/api/validate.py @@ -15,7 +15,7 @@ from langflow.utils.logger import logger from langflow.utils.validate import validate_code # build router -router = APIRouter(prefix="/validate", tags=["validate"]) +router = APIRouter(prefix="/validate", tags=["Validate"]) @router.post("/code", status_code=200, response_model=CodeValidationResponse) diff --git a/src/backend/langflow/main.py b/src/backend/langflow/main.py index 56cc32e46..75c19bd25 100644 --- a/src/backend/langflow/main.py +++ b/src/backend/langflow/main.py @@ -4,6 +4,14 @@ from fastapi.middleware.cors import CORSMiddleware from langflow.api.chat import router as chat_router from langflow.api.endpoints import router as endpoints_router from langflow.api.validate import router as validate_router +from langflow.api.database import router as database_router +from langflow.utils.logger import logger +from langflow.database.base import create_db_and_tables +from fastapi import APIRouter, HTTPException + + +# build router +router = APIRouter() def create_app(): @@ -25,6 +33,10 @@ def create_app(): app.include_router(endpoints_router) app.include_router(validate_router) app.include_router(chat_router) + app.include_router(database_router) + + app.on_event("startup")(create_db_and_tables) + return app