diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index 5ce1ff2ab..52c8e9a67 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -6,7 +6,8 @@ from fastapi import ( WebSocketException, status, ) -from fastapi.responses import StreamingResponse, JSONResponse +from fastapi.responses import StreamingResponse +from langflow.api.v1.schemas import BuiltResponse, InitResponse from langflow.chat.manager import ChatManager from langflow.graph.graph.base import Graph @@ -31,7 +32,7 @@ async def chat(client_id: str, websocket: WebSocket): await websocket.close(code=status.WS_1011_INTERNAL_ERROR, reason=str(exc)) -@router.post("/build/init") +@router.post("/build/init", response_model=InitResponse) async def init_build(graph_data: dict): """Initialize the build by storing graph data and returning a unique session ID.""" @@ -39,19 +40,21 @@ async def init_build(graph_data: dict): flow_data_store[flow_id] = graph_data - return JSONResponse(content={"flowId": flow_id}) + return InitResponse(flowId=flow_id) -@router.get("/build/{flow_id}/status") +@router.get("/build/{flow_id}/status", response_model=BuiltResponse) async def build_status(flow_id: str): """Check the flow_id is in the flow_data_store.""" try: - if flow_id in flow_data_store and not isinstance( + built = flow_id in flow_data_store and not isinstance( flow_data_store[flow_id], dict - ): - return JSONResponse(content={"built": True}) - else: - return JSONResponse(content={"built": False}) + ) + + return BuiltResponse( + built=built, + ) + except Exception as exc: logger.error(exc) return HTTPException(status_code=500, detail=str(exc)) diff --git a/src/backend/langflow/api/v1/schemas.py b/src/backend/langflow/api/v1/schemas.py index f73b0642d..161704738 100644 --- a/src/backend/langflow/api/v1/schemas.py +++ b/src/backend/langflow/api/v1/schemas.py @@ -68,3 +68,11 @@ class FileResponse(ChatMessage): if v not in ["image", "csv"]: raise ValueError("data_type must be image or csv") return v + + +class InitResponse(BaseModel): + flowId: str + + +class BuiltResponse(BaseModel): + built: bool diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 04dbcdf04..22f9d4fcd 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -50,7 +50,7 @@ export default function App() { // Initialize state variable for the version const [version, setVersion] = useState(""); useEffect(() => { - fetch("/version") + fetch("api/v1/version") .then((res) => res.json()) .then((data) => { setVersion(data.version); diff --git a/src/frontend/src/components/chatComponent/buildTrigger/index.tsx b/src/frontend/src/components/chatComponent/buildTrigger/index.tsx index 31832d974..22b052aa7 100644 --- a/src/frontend/src/components/chatComponent/buildTrigger/index.tsx +++ b/src/frontend/src/components/chatComponent/buildTrigger/index.tsx @@ -1,16 +1,13 @@ -import { useState, useContext, useRef, useEffect } from "react"; +import { useState, useContext } from "react"; import { Transition } from "@headlessui/react"; -import { Bars3CenterLeftIcon } from "@heroicons/react/24/outline"; import { Zap } from "lucide-react"; -import { nodeColors, validateNodes } from "../../../utils"; -import { PopUpContext } from "../../../contexts/popUpContext"; -import ChatModal from "../../../modals/chatModal"; +import { validateNodes } from "../../../utils"; import { FlowType } from "../../../types/flow"; import Loading from "../../../components/ui/loading"; import { useSSE } from "../../../contexts/SSEContext"; -import axios from "axios"; import { typesContext } from "../../../contexts/typesContext"; import { alertContext } from "../../../contexts/alertContext"; +import { postBuildInit } from "../../../controllers/API"; export default function BuildTrigger({ open, @@ -26,21 +23,24 @@ export default function BuildTrigger({ const [isBuilding, setIsBuilding] = useState(false); const { updateSSEData } = useSSE(); - const {reactFlowInstance} = useContext(typesContext); - const {setErrorData} = useContext(alertContext) + const { reactFlowInstance } = useContext(typesContext); + const { setErrorData } = useContext(alertContext); async function handleBuild(flow: FlowType) { - const errors = validateNodes(reactFlowInstance) - if(errors.length > 0) { - setErrorData({title: "Oops! Looks like you missed something", list: errors}) - return + const errors = validateNodes(reactFlowInstance); + if (errors.length > 0) { + setErrorData({ + title: "Oops! Looks like you missed something", + list: errors, + }); + return; } const minimumLoadingTime = 200; // in milliseconds const startTime = Date.now(); setIsBuilding(true); try { - const allNodesValid = await streamNodeData(`/build/init`, flow); + const allNodesValid = await streamNodeData(flow); await enforceMinimumLoadingTime(startTime, minimumLoadingTime); setIsBuilt(allNodesValid); } catch (error) { @@ -50,15 +50,15 @@ export default function BuildTrigger({ } } - async function streamNodeData(apiUrl: string, flow: FlowType) { + async function streamNodeData(flow: FlowType) { // Step 1: Make a POST request to send the flow data and receive a unique session ID - const response = await axios.post(apiUrl, flow); + const response = await postBuildInit(flow); const { flowId } = response.data; // Step 2: Use the session ID to establish an SSE connection using EventSource let validationResults = []; let finished = false; - apiUrl = `/build/stream/${flowId}`; + const apiUrl = `/build/stream/${flowId}`; const eventSource = new EventSource(apiUrl); try{ eventSource.onmessage = (event) => { @@ -134,7 +134,9 @@ export default function BuildTrigger({