Merge branch 'validation_fix' of personal:logspace-ai/langflow into validation_fix
This commit is contained in:
commit
1a6406e394
7 changed files with 61 additions and 40 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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({
|
|||
<div className={`fixed right-4` + (isBuilt ? " bottom-20" : " bottom-4")}>
|
||||
<div
|
||||
className="border flex justify-center align-center py-1 px-3 w-12 h-12 rounded-full bg-gradient-to-r from-blue-700 via-blue-600 to-blue-500 dark:border-gray-600 cursor-pointer"
|
||||
onClick={() => {if(!isBuilding) handleBuild(flow)}}
|
||||
onClick={() => {
|
||||
if (!isBuilding) handleBuild(flow);
|
||||
}}
|
||||
>
|
||||
<button>
|
||||
<div className="flex gap-3 items-center">
|
||||
|
|
|
|||
|
|
@ -2,29 +2,30 @@ import {
|
|||
BuildStatusTypeAPI,
|
||||
PromptTypeAPI,
|
||||
errorsTypeAPI,
|
||||
InitTypeAPI,
|
||||
} from "./../../types/api/index";
|
||||
import { APIObjectType, sendAllProps } from "../../types/api/index";
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import { FlowType } from "../../types/flow";
|
||||
|
||||
export async function getAll(): Promise<AxiosResponse<APIObjectType>> {
|
||||
return await axios.get(`/all`);
|
||||
return await axios.get(`/api/v1/all`);
|
||||
}
|
||||
|
||||
export async function sendAll(data: sendAllProps) {
|
||||
return await axios.post(`/predict`, data);
|
||||
return await axios.post(`/api/v1/predict`, data);
|
||||
}
|
||||
|
||||
export async function checkCode(
|
||||
code: string
|
||||
): Promise<AxiosResponse<errorsTypeAPI>> {
|
||||
return await axios.post("/validate/code", { code });
|
||||
return await axios.post("/api/v1/validate/code", { code });
|
||||
}
|
||||
|
||||
export async function checkPrompt(
|
||||
template: string
|
||||
): Promise<AxiosResponse<PromptTypeAPI>> {
|
||||
return await axios.post("/validate/prompt", { template });
|
||||
return await axios.post("/api/v1/validate/prompt", { template });
|
||||
}
|
||||
|
||||
export async function getExamples(): Promise<FlowType[]> {
|
||||
|
|
@ -47,5 +48,11 @@ export async function getExamples(): Promise<FlowType[]> {
|
|||
export async function getBuildStatus(
|
||||
flowId: string
|
||||
): Promise<BuildStatusTypeAPI> {
|
||||
return await axios.get(`/build/${flowId}/status`);
|
||||
return await axios.get(`/api/v1/build/${flowId}/status`);
|
||||
}
|
||||
|
||||
export async function postBuildInit(
|
||||
flow: FlowType
|
||||
): Promise<AxiosResponse<InitTypeAPI>> {
|
||||
return await axios.post(`/api/v1/build/init`, flow);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,3 +42,7 @@ export type PromptTypeAPI = { input_variables: Array<string> };
|
|||
export type BuildStatusTypeAPI = {
|
||||
built: boolean;
|
||||
};
|
||||
|
||||
export type InitTypeAPI = {
|
||||
flowId: string;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ import { defineConfig } from "vite";
|
|||
import react from "@vitejs/plugin-react-swc";
|
||||
import svgr from "vite-plugin-svgr";
|
||||
const apiRoutes = [
|
||||
"/all",
|
||||
"/predict",
|
||||
"^/validate/*",
|
||||
"^/chat/*",
|
||||
"/version",
|
||||
"/api/v1/all",
|
||||
"/api/v1/predict",
|
||||
"^/api/v1/validate/*",
|
||||
"/api/v1/chat/*",
|
||||
"/api/v1/version",
|
||||
"/health",
|
||||
"^/build/*",
|
||||
];
|
||||
|
||||
// Use environment variable to determine the target.
|
||||
|
|
@ -20,11 +19,9 @@ const proxyTargets = apiRoutes.reduce((proxyObj, route) => {
|
|||
changeOrigin: true,
|
||||
secure: false,
|
||||
ws: true,
|
||||
rewrite: (path) => `/api/v1${path}`,
|
||||
};
|
||||
return proxyObj;
|
||||
}, {});
|
||||
|
||||
export default defineConfig(() => {
|
||||
return {
|
||||
build: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue