Merge branch 'validation_fix' of personal:logspace-ai/langflow into validation_fix

This commit is contained in:
anovazzi1 2023-06-13 18:45:57 -03:00
commit 1a6406e394
7 changed files with 61 additions and 40 deletions

View file

@ -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))

View file

@ -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

View file

@ -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);

View file

@ -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">

View file

@ -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);
}

View file

@ -42,3 +42,7 @@ export type PromptTypeAPI = { input_variables: Array<string> };
export type BuildStatusTypeAPI = {
built: boolean;
};
export type InitTypeAPI = {
flowId: string;
};

View file

@ -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: {