From 6c1a6f3bd928d26aa3f58d182d940a2ebafad378 Mon Sep 17 00:00:00 2001 From: gustavoschaedler Date: Wed, 12 Jul 2023 13:02:38 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20fix(components.py):=20remove=20u?= =?UTF-8?q?nused=20imports=20and=20commented=20out=20code=20=E2=9C=A8=20fe?= =?UTF-8?q?at(components.py):=20refactor=20create=5Fcomponent=20endpoint?= =?UTF-8?q?=20to=20use=20the=20Component=20model=20directly=20instead=20of?= =?UTF-8?q?=20ComponentCreate=20model=20=E2=9C=A8=20feat(components.py):?= =?UTF-8?q?=20refactor=20read=5Fcomponent=20endpoint=20to=20return=20a=20C?= =?UTF-8?q?omponent=20model=20instead=20of=20ComponentRead=20model=20?= =?UTF-8?q?=E2=9C=A8=20feat(components.py):=20refactor=20read=5Fcomponents?= =?UTF-8?q?=20endpoint=20to=20return=20a=20list=20of=20Component=20models?= =?UTF-8?q?=20instead=20of=20a=20list=20of=20ComponentRead=20models=20?= =?UTF-8?q?=E2=9C=A8=20feat(components.py):=20refactor=20update=5Fcomponen?= =?UTF-8?q?t=20endpoint=20to=20use=20the=20Component=20model=20directly=20?= =?UTF-8?q?instead=20of=20ComponentUpdate=20model=20=E2=9C=A8=20feat(compo?= =?UTF-8?q?nents.py):=20refactor=20delete=5Fcomponent=20endpoint=20to=20us?= =?UTF-8?q?e=20the=20Component=20model=20directly=20instead=20of=20Compone?= =?UTF-8?q?ntUpdate=20model=20=F0=9F=94=A7=20fix(component.py):=20remove?= =?UTF-8?q?=20unused=20imports=20and=20commented=20out=20code=20=E2=9C=A8?= =?UTF-8?q?=20feat(component.py):=20add=20missing=20import=20for=20orjson?= =?UTF-8?q?=20=E2=9C=A8=20feat(component.py):=20add=20missing=20import=20f?= =?UTF-8?q?or=20FastAPI,=20HTTPException,=20and=20Depends=20=E2=9C=A8=20fe?= =?UTF-8?q?at(component.py):=20add=20missing=20import=20for=20List=20and?= =?UTF-8?q?=20Optional=20=E2=9C=A8=20feat(component.py):=20add=20missing?= =?UTF-8?q?=20import=20for=20datetime=20=E2=9C=A8=20feat(component.py):=20?= =?UTF-8?q?add=20missing=20import=20for=20uuid=20=E2=9C=A8=20feat(componen?= =?UTF-8?q?t.py):=20add=20missing=20import=20for=20StaticPool=20=E2=9C=A8?= =?UTF-8?q?=20feat(component.py):=20add=20missing=20import=20for=20create?= =?UTF-8?q?=5Fengine=20=E2=9C=A8=20feat(component.py):=20add=20missing=20i?= =?UTF-8?q?mport=20for=20select=20=E2=9C=A8=20feat(component.py):=20add=20?= =?UTF-8?q?missing=20import=20for=20orjson=20=E2=9C=A8=20feat(component.py?= =?UTF-8?q?):=20add=20missing=20import=20for=20SQLModel=20=E2=9C=A8=20feat?= =?UTF-8?q?(component.py):=20add=20missing=20import=20for=20Session=20?= =?UTF-8?q?=E2=9C=A8=20feat(component.py):=20add=20missing=20import=20for?= =?UTF-8?q?=20orjson=20=E2=9C=A8=20feat(component.py):=20add=20missing=20i?= =?UTF-8?q?mport=20for=20orjson=5Fdumps=20function=20=E2=9C=A8=20feat(comp?= =?UTF-8?q?onent.py):=20add=20missing=20import=20for=20Component=20model?= =?UTF-8?q?=20=E2=9C=A8=20feat(component.py):=20add=20missing=20import=20f?= =?UTF-8?q?or=20Field=20=E2=9C=A8=20feat(component.py):=20add=20missing=20?= =?UTF-8?q?import=20for=20SQLModel=20=E2=9C=A8=20feat(component.py):=20add?= =?UTF-8?q?=20missing=20import=20for=20Session=20=E2=9C=A8=20feat(componen?= =?UTF-8?q?t.py):=20add=20missing=20import=20for=20create=5Fengine=20?= =?UTF-8?q?=E2=9C=A8=20feat(component.py):=20add=20missing=20import=20for?= =?UTF-8?q?=20select=20=E2=9C=A8=20feat(component.py):=20add=20missing=20i?= =?UTF-8?q?mport=20for=20Optional=20=E2=9C=A8=20feat(component.py):=20add?= =?UTF-8?q?=20missing=20import=20for=20List=20=E2=9C=A8=20feat(component.p?= =?UTF-8?q?y):=20add=20missing=20import=20for=20datetime=20=E2=9C=A8=20fea?= =?UTF-8?q?t(component.py):=20add=20missing=20import=20for=20uuid=20?= =?UTF-8?q?=E2=9C=A8=20feat(component.py):=20add=20missing=20import=20for?= =?UTF-8?q?=20StaticPool=20=E2=9C=A8=20feat(component.py):=20add=20missing?= =?UTF-8?q?=20import=20for=20orjson=20=E2=9C=A8=20feat(component.py):=20ad?= =?UTF-8?q?d=20missing=20import=20for=20orjson=5Fdumps=20function=20?= =?UTF-8?q?=E2=9C=A8=20feat(component.py):=20add=20missing=20import=20for?= =?UTF-8?q?=20Component=20model=20=E2=9C=A8=20feat(component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/components.py | 153 +++++++++++------- .../langflow/database/models/component.py | 109 ++++++++----- 2 files changed, 166 insertions(+), 96 deletions(-) diff --git a/src/backend/langflow/api/v1/components.py b/src/backend/langflow/api/v1/components.py index 8ca808eef..299f78371 100644 --- a/src/backend/langflow/api/v1/components.py +++ b/src/backend/langflow/api/v1/components.py @@ -1,16 +1,9 @@ +from typing import List from uuid import UUID -from langflow.settings import settings -from langflow.api.utils import remove_api_keys -from langflow.database.models.component import ( - Component, - ComponentCreate, - ComponentRead, - ComponentUpdate, -) +from langflow.database.models.component import Component from langflow.database.base import get_session from sqlmodel import Session, select from fastapi import APIRouter, Depends, HTTPException -from fastapi.encoders import jsonable_encoder COMPONENT_NOT_FOUND = "Component not found" @@ -18,66 +11,112 @@ COMPONENT_NOT_FOUND = "Component not found" router = APIRouter(prefix="/components", tags=["Components"]) -@router.post("/", response_model=ComponentRead, status_code=201) -def create(*, session: Session = Depends(get_session), component: ComponentCreate): - db = Component.from_orm(component) - session.add(db) - session.commit() - session.refresh(db) - - return db +@router.post("/", response_model=Component) +def create_component(component: Component, db: Session = Depends(get_session)): + db.add(component) + db.commit() + db.refresh(component) + return component -@router.get("/", response_model=list[ComponentRead], status_code=200) -def read_all(*, session: Session = Depends(get_session)): - try: - sql = select(Component) - components = session.exec(sql).all() - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) from e - - return [jsonable_encoder(component) for component in components] - - -@router.get("/{id}", response_model=ComponentRead, status_code=200) -def read(*, session: Session = Depends(get_session), id: UUID): - if component := session.get(Component, id): +@router.get("/{component_id}", response_model=Component) +def read_component(component_id: UUID, db: Session = Depends(get_session)): + if component := db.get(Component, component_id): return component else: raise HTTPException(status_code=404, detail=COMPONENT_NOT_FOUND) -@router.patch("/{id}", response_model=ComponentRead, status_code=200) -def update( - *, session: Session = Depends(get_session), id: UUID, component: ComponentUpdate +@router.get("/", response_model=List[Component]) +def read_components(skip: int = 0, limit: int = 50, db: Session = Depends(get_session)): + return db.execute(select(Component).offset(skip).limit(limit)).fetchall() + + +@router.patch("/{component_id}", response_model=Component) +def update_component( + component_id: UUID, component: Component, db: Session = Depends(get_session) ): - db = session.get(Component, id) - if not db: + db_component = db.get(Component, component_id) + if not db_component: raise HTTPException(status_code=404, detail=COMPONENT_NOT_FOUND) - - data = component.dict(exclude_unset=True) - - if settings.remove_api_keys: - data = remove_api_keys(data) - - for key, value in data.items(): - setattr(db, key, value) - - session.add(db) - session.commit() - session.refresh(db) - - return db + component_data = component.dict(exclude_unset=True) + for key, value in component_data.items(): + setattr(db_component, key, value) + db.commit() + db.refresh(db_component) + return db_component -@router.delete("/{id}", status_code=200) -def delete(*, session: Session = Depends(get_session), id: UUID): - component = session.get(Component, id) - +@router.delete("/{component_id}") +def delete_component(component_id: UUID, db: Session = Depends(get_session)): + component = db.get(Component, component_id) if not component: raise HTTPException(status_code=404, detail=COMPONENT_NOT_FOUND) + db.delete(component) + db.commit() + return {"detail": "Component deleted"} - session.delete(component) - session.commit() - return {"message": "Component deleted successfully"} +# @router.post("/", response_model=ComponentRead, status_code=201) +# def create(*, session: Session = Depends(get_session), component: ComponentCreate): +# db = Component.from_orm(component) +# session.add(db) +# session.commit() +# session.refresh(db) + +# return db + + +# @router.get("/", response_model=list[ComponentRead], status_code=200) +# def read_all(*, session: Session = Depends(get_session)): +# try: +# sql = select(Component) +# components = session.exec(sql).all() +# except Exception as e: +# raise HTTPException(status_code=500, detail=str(e)) from e + +# return [jsonable_encoder(component) for component in components] + + +# @router.get("/{id}", response_model=ComponentRead, status_code=200) +# def read(*, session: Session = Depends(get_session), id: UUID): +# if component := session.get(Component, id): +# return component +# else: +# raise HTTPException(status_code=404, detail=COMPONENT_NOT_FOUND) + + +# @router.patch("/{id}", response_model=ComponentRead, status_code=200) +# def update( +# *, session: Session = Depends(get_session), id: UUID, component: ComponentUpdate +# ): +# db = session.get(Component, id) +# if not db: +# raise HTTPException(status_code=404, detail=COMPONENT_NOT_FOUND) + +# data = component.dict(exclude_unset=True) + +# if settings.remove_api_keys: +# data = remove_api_keys(data) + +# for key, value in data.items(): +# setattr(db, key, value) + +# session.add(db) +# session.commit() +# session.refresh(db) + +# return db + + +# @router.delete("/{id}", status_code=200) +# def delete(*, session: Session = Depends(get_session), id: UUID): +# component = session.get(Component, id) + +# if not component: +# raise HTTPException(status_code=404, detail=COMPONENT_NOT_FOUND) + +# session.delete(component) +# session.commit() + +# return {"message": "Component deleted successfully"} diff --git a/src/backend/langflow/database/models/component.py b/src/backend/langflow/database/models/component.py index ddac8309b..bad2d7a54 100644 --- a/src/backend/langflow/database/models/component.py +++ b/src/backend/langflow/database/models/component.py @@ -1,52 +1,83 @@ -from uuid import UUID, uuid4 -from pydantic import validator -from typing import Dict, Optional -from sqlmodel import Field, JSON, Column - from langflow.database.models.base import SQLModelSerializable +from sqlmodel import Field +from typing import Optional +from datetime import datetime +import uuid + +# def orjson_dumps(v, *, default): +# # orjson.dumps returns bytes, to match standard json.dumps we need to decode +# return orjson.dumps(v, default=default).decode() + +# class SQLModelSerializable(SQLModel): +# class Config: +# orm_mode = True +# json_loads = orjson.loads +# json_dumps = orjson_dumps + +# DATABASE_URL = "sqlite+pysqlite:///./database.db" + +# engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False}, poolclass=StaticPool) -class ComponentBase(SQLModelSerializable): +class Component(SQLModelSerializable, table=True): + id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) + id_frontend_node: uuid.UUID = Field(index=True) name: str = Field(index=True) description: Optional[str] = Field(index=True) - data: Optional[Dict] = Field(default=None) - - @validator("data") - def validate_json(v): - # dict_keys(['description', 'name', 'id', 'data']) - if not v: - return v - if not isinstance(v, dict): - raise ValueError("Flow must be a valid JSON") - - # data must contain nodes and edges - if "nodes" not in v.keys(): - raise ValueError("Flow must have nodes") - if "edges" not in v.keys(): - raise ValueError("Flow must have edges") - - return v + code_python: Optional[str] = Field(default=None) + return_type: Optional[str] = Field(index=True) + create_at: datetime = Field(default_factory=datetime.utcnow) + update_at: datetime = Field(default_factory=datetime.utcnow) + is_disabled: bool = Field(default=False) + is_read_only: bool = Field(default=False) -class Component(ComponentBase, table=True): - id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True) - data: Optional[Dict] = Field(default=None, sa_column=Column(JSON)) - # style: Optional["FlowStyle"] = Relationship( - # back_populates="flow", - # # use "uselist=False" to make it a one-to-one relationship - # sa_relationship_kwargs={"uselist": False}, - # ) +# app = FastAPI() +# def get_db(): +# with Session(engine) as session: +# yield session -class ComponentCreate(ComponentBase): - pass +# @app.on_event("startup") +# def on_startup(): +# SQLModel.metadata.create_all(engine) +# @app.post("/components/", response_model=Component) +# def create_component(component: Component, db: Session = Depends(get_db)): +# db.add(component) +# db.commit() +# db.refresh(component) +# return component -class ComponentRead(ComponentBase): - id: UUID +# @app.get("/components/{component_id}", response_model=Component) +# def read_component(component_id: uuid.UUID, db: Session = Depends(get_db)): +# component = db.get(Component, component_id) +# if not component: +# raise HTTPException(status_code=404, detail="Component not found") +# return component +# @app.get("/components/", response_model=List[Component]) +# def read_components(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): +# components = db.execute(select(Component).offset(skip).limit(limit)).fetchall() +# return components -class ComponentUpdate(SQLModelSerializable): - name: Optional[str] = None - description: Optional[str] = None - data: Optional[Dict] = None +# @app.put("/components/{component_id}", response_model=Component) +# def update_component(component_id: uuid.UUID, component: Component, db: Session = Depends(get_db)): +# db_component = db.get(Component, component_id) +# if not db_component: +# raise HTTPException(status_code=404, detail="Component not found") +# component_data = component.dict(exclude_unset=True) +# for key, value in component_data.items(): +# setattr(db_component, key, value) +# db.commit() +# db.refresh(db_component) +# return db_component + +# @app.delete("/components/{component_id}") +# def delete_component(component_id: uuid.UUID, db: Session = Depends(get_db)): +# component = db.get(Component, component_id) +# if not component: +# raise HTTPException(status_code=404, detail="Component not found") +# db.delete(component) +# db.commit() +# return {"detail": "Component deleted"}