diff --git a/src/backend/langflow/api/v1/flow_styles.py b/src/backend/langflow/api/v1/flow_styles.py new file mode 100644 index 000000000..40e292eb3 --- /dev/null +++ b/src/backend/langflow/api/v1/flow_styles.py @@ -0,0 +1,83 @@ +from uuid import UUID +from langflow.database.models.flow_style import ( + FlowStyle, + FlowStyleCreate, + FlowStyleRead, + FlowStyleUpdate, +) +from langflow.database.base import get_session +from sqlmodel import Session, select +from fastapi import APIRouter, Depends, HTTPException + + +# build router +router = APIRouter(prefix="/flow_styles", tags=["FlowStyles"]) + +# FlowStyleCreate: +# class FlowStyleBase(SQLModel): +# color: str = Field(index=True) +# emoji: str = Field(index=False) +# flow_id: UUID = Field(default=None, foreign_key="flow.id") + + +@router.post("/", response_model=FlowStyleRead) +def create_flow_style( + *, session: Session = Depends(get_session), flow_style: FlowStyleCreate +): + """Create a new flow_style.""" + db_flow_style = FlowStyle.from_orm(flow_style) + session.add(db_flow_style) + session.commit() + session.refresh(db_flow_style) + return db_flow_style + + +@router.get("/", response_model=list[FlowStyleRead]) +def read_flow_styles(*, session: Session = Depends(get_session)): + """Read all flows.""" + try: + flows = session.exec(select(FlowStyle)).all() + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e + return flows + + +@router.get("/{flow_styles_id}", response_model=FlowStyleRead) +def read_flow_style(*, session: Session = Depends(get_session), flow_styles_id: UUID): + """Read a flow_style.""" + if flow_style := session.get(FlowStyle, flow_styles_id): + return flow_style + else: + raise HTTPException(status_code=404, detail="FlowStyle not found") + + +@router.patch("/{flow_style_id}", response_model=FlowStyleRead) +def update_flow_style( + *, + session: Session = Depends(get_session), + flow_style_id: UUID, + flow_style: FlowStyleUpdate, +): + """Update a flow_style.""" + db_flow_style = session.get(FlowStyle, flow_style_id) + if not db_flow_style: + raise HTTPException(status_code=404, detail="FlowStyle not found") + flow_data = flow_style.dict(exclude_unset=True) + for key, value in flow_data.items(): + if hasattr(db_flow_style, key) and value is not None: + setattr(db_flow_style, key, value) + session.add(db_flow_style) + session.commit() + session.refresh(db_flow_style) + return db_flow_style + + +@router.delete("/{flow_id}") +def delete_flow_style(*, session: Session = Depends(get_session), flow_id: UUID): + """Delete a flow_style.""" + flow_style = session.get(FlowStyle, flow_id) + if not flow_style: + raise HTTPException(status_code=404, detail="FlowStyle not found") + session.delete(flow_style) + session.commit() + return {"message": "FlowStyle deleted successfully"} diff --git a/src/backend/langflow/api/v1/flows.py b/src/backend/langflow/api/v1/flows.py new file mode 100644 index 000000000..d047cbcd5 --- /dev/null +++ b/src/backend/langflow/api/v1/flows.py @@ -0,0 +1,115 @@ +from typing import List +from uuid import UUID +from langflow.api.v1.schemas import FlowListCreate, FlowListRead +from langflow.database.models.flow import ( + Flow, + FlowCreate, + FlowRead, + FlowReadWithStyle, + FlowUpdate, +) +from langflow.database.base import get_session +from sqlmodel import Session, select +from fastapi import APIRouter, Depends, HTTPException +from fastapi.encoders import jsonable_encoder + +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[FlowReadWithStyle]) +def read_flows(*, session: Session = Depends(get_session)): + """Read all flows.""" + try: + flows = session.exec(select(Flow)).all() + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e + return [jsonable_encoder(flow) for flow in flows] + + +@router.get("/{flow_id}", response_model=FlowReadWithStyle) +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.patch("/{flow_id}", response_model=FlowRead) +def update_flow( + *, session: Session = Depends(get_session), flow_id: UUID, flow: FlowUpdate +): + """Update a flow.""" + db_flow = session.get(Flow, flow_id) + if not db_flow: + raise HTTPException(status_code=404, detail="Flow not found") + flow_data = flow.dict(exclude_unset=True) + for key, value in flow_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) + if "flows" in data: + flow_list = FlowListCreate(**data) + else: + flow_list = FlowListCreate(flows=[FlowCreate(**flow) for flow in data]) + return create_flows(session=session, flow_list=flow_list) + + +@router.get("/download/", response_model=FlowListRead) +async def download_file(*, session: Session = Depends(get_session)): + """Download all flows as a file.""" + flows = read_flows(session=session) + return FlowListRead(flows=flows) diff --git a/src/backend/langflow/database/models/flowstyle.py b/src/backend/langflow/database/models/flowstyle.py deleted file mode 100644 index cb3fb9b2b..000000000 --- a/src/backend/langflow/database/models/flowstyle.py +++ /dev/null @@ -1,25 +0,0 @@ -from sqlmodel import Field, SQLModel, Relationship -from uuid import UUID, uuid4 -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from langflow.database.models.flow import Flow - - -class FlowStyleBase(SQLModel): - color: str = Field(index=True) - emoji: str = Field(index=False) - flow_id: UUID = Field(default_factory=uuid4, foreign_key="flow.id") - flow: "Flow" = Relationship(back_populates="style") - - -class FlowStyle(FlowStyleBase, table=True): - id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True) - - -class FlowStyleCreate(FlowStyleBase): - pass - - -class FlowStyleRead(FlowStyleBase): - id: UUID