Validation_fix (#317)

This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-05-17 14:21:52 -03:00 • committed by GitHub
commit 0ed4475c6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 142 additions and 116 deletions

View file

@ -1,5 +1,5 @@
from importlib.metadata import version
import logging import logging
from importlib.metadata import version
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException

View file

@ -54,4 +54,4 @@ def post_validate_node(node_id: str, data: dict):
return json.dumps({"valid": True, "params": str(node._built_object_repr())}) return json.dumps({"valid": True, "params": str(node._built_object_repr())})
except Exception as e: except Exception as e:
logger.exception(e) logger.exception(e)
return json.dumps({"valid": False}) return json.dumps({"valid": False, "params": str(e)})

View file

@ -3,12 +3,12 @@ import io
from typing import Any, Dict, List, Tuple from typing import Any, Dict, List, Tuple
from chromadb.errors import NotEnoughElementsException # type: ignore from chromadb.errors import NotEnoughElementsException # type: ignore
from langchain.schema import AgentAction
from langflow.api.callback import AsyncStreamingLLMCallbackHandler, StreamingLLMCallbackHandler # type: ignore from langflow.api.callback import AsyncStreamingLLMCallbackHandler, StreamingLLMCallbackHandler # type: ignore
from langflow.cache.base import compute_dict_hash, load_cache, memoize_dict from langflow.cache.base import compute_dict_hash, load_cache, memoize_dict
from langflow.graph.graph import Graph from langflow.graph.graph import Graph
from langflow.utils.logger import logger from langflow.utils.logger import logger
from langchain.schema import AgentAction
def load_langchain_object(data_graph, is_first_message=False): def load_langchain_object(data_graph, is_first_message=False):

View file

@ -1,4 +1,12 @@
import { BugAntIcon, Cog6ToothIcon, ExclamationCircleIcon, InformationCircleIcon, TrashIcon } from "@heroicons/react/24/outline"; import {
BugAntIcon,
CheckCircleIcon,
Cog6ToothIcon,
EllipsisHorizontalCircleIcon,
ExclamationCircleIcon,
InformationCircleIcon,
TrashIcon,
} from "@heroicons/react/24/outline";
import { classNames, nodeColors, nodeIcons, toNormalCase } from "../../utils"; import { classNames, nodeColors, nodeIcons, toNormalCase } from "../../utils";
import ParameterComponent from "./components/parameterComponent"; import ParameterComponent from "./components/parameterComponent";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
@ -12,11 +20,11 @@ import { TabsContext } from "../../contexts/tabsContext";
import { debounce } from "../../utils"; import { debounce } from "../../utils";
import Tooltip from "../../components/TooltipComponent"; import Tooltip from "../../components/TooltipComponent";
export default function GenericNode({ export default function GenericNode({
data, data,
selected, selected,
}: { }: {
data: NodeDataType; data: NodeDataType;
selected: boolean; selected: boolean;
}) { }) {
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
const showError = useRef(true); const showError = useRef(true);
@ -30,32 +38,28 @@ export default function GenericNode({
const { reactFlowInstance } = useContext(typesContext); const { reactFlowInstance } = useContext(typesContext);
const [params, setParams] = useState([]); const [params, setParams] = useState([]);
useEffect(() => { useEffect(() => {
if (reactFlowInstance) { if (reactFlowInstance) {
setParams(Object.values(reactFlowInstance.toObject())); setParams(Object.values(reactFlowInstance.toObject()));
} }
}, [save]); }, [save]);
const validateNode = useCallback( const validateNode = useCallback(
debounce(async () => { debounce(async () => {
try { try {
const response = await fetch(`/validate/node/${data.id}`, { const response = await fetch(`/validate/node/${data.id}`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify(reactFlowInstance.toObject()), body: JSON.stringify(reactFlowInstance.toObject()),
}); });
if (response.status === 200) { if (response.status === 200) {
let jsonResponse = await response.json(); let jsonResponse = await response.json();
let jsonResponseParsed = await JSON.parse(jsonResponse); let jsonResponseParsed = await JSON.parse(jsonResponse);
console.log(jsonResponseParsed); console.log(jsonResponseParsed);
if(jsonResponseParsed.valid){ setValidationStatus(jsonResponseParsed);
setValidationStatus(jsonResponseParsed.params);
} else {
setValidationStatus("error");
}
} }
} catch (error) { } catch (error) {
// console.error("Error validating node:", error); // console.error("Error validating node:", error);
@ -70,31 +74,22 @@ export default function GenericNode({
} }
}, [params, validateNode]); }, [params, validateNode]);
useEffect(() => { if (!Icon) {
if (validationStatus !== "error") { if (showError.current) {
setIsValid(true); setErrorData({
} else { title: data.type
setIsValid(false); ? `The ${data.type} node could not be rendered, please review your json file`
: "There was a node that can't be rendered, please review your json file",
});
showError.current = false;
} }
}, [validationStatus]); deleteNode(data.id);
return;
if (!Icon) { }
if (showError.current) {
setErrorData({
title: data.type
? `The ${data.type} node could not be rendered, please review your json file`
: "There was a node that can't be rendered, please review your json file",
});
showError.current = false;
}
deleteNode(data.id);
return;
}
return ( return (
<div <div
className={classNames( className={classNames(
isValid ? "animate-pulse-green" : "border-red-outline",
selected ? "border border-blue-500" : "border dark:border-gray-700", selected ? "border border-blue-500" : "border dark:border-gray-700",
"prompt-node relative bg-white dark:bg-gray-900 w-96 rounded-lg flex flex-col justify-center" "prompt-node relative bg-white dark:bg-gray-900 w-96 rounded-lg flex flex-col justify-center"
)} )}
@ -108,15 +103,46 @@ export default function GenericNode({
}} }}
/> />
<div className="ml-2 truncate">{data.type}</div> <div className="ml-2 truncate">{data.type}</div>
{validationStatus && validationStatus !== "error" ? <div>
<Tooltip title={ <Tooltip
<div className="max-h-96 overflow-auto"> title={
{validationStatus} !validationStatus ? (
</div>}> "Validating..."
<ExclamationCircleIcon className="w-5 hover:text-gray-500 hover:dark:text-gray-300" /> ) : (
</Tooltip> <div className="max-h-96 overflow-auto">
: <></> {validationStatus.params}
} </div>
)
}
>
<div className="relative w-5 h-5">
<CheckCircleIcon
className={classNames(
validationStatus && validationStatus.valid
? "text-green-500 opacity-100"
: "text-green-500 opacity-0 animate-spin",
"absolute w-5 hover:text-gray-500 hover:dark:text-gray-300 transition-all ease-in-out duration-200"
)}
/>
<ExclamationCircleIcon
className={classNames(
validationStatus && !validationStatus.valid
? "text-red-500 opacity-100"
: "text-red-500 opacity-0 animate-spin",
"w-5 absolute hover:text-gray-500 hover:dark:text-gray-600 transition-all ease-in-out duration-200"
)}
/>
<EllipsisHorizontalCircleIcon
className={classNames(
!validationStatus
? "text-yellow-500 opacity-100"
: "text-yellow-500 opacity-0 animate-spin",
"w-5 absolute hover:text-gray-500 hover:dark:text-gray-600 transition-all ease-in-out duration-300"
)}
/>
</div>
</Tooltip>
</div>
</div> </div>
<div className="flex gap-3"> <div className="flex gap-3">
<button <button
@ -162,12 +188,12 @@ export default function GenericNode({
{data.node.description} {data.node.description}
</div> </div>
<> <>
{Object.keys(data.node.template) {Object.keys(data.node.template)
.filter((t) => t.charAt(0) !== "_") .filter((t) => t.charAt(0) !== "_")
.map((t: string, idx) => ( .map((t: string, idx) => (
<div key={idx}> <div key={idx}>
{/* {idx === 0 ? ( {/* {idx === 0 ? (
<div <div
className={classNames( className={classNames(
"px-5 py-2 mt-2 dark:text-white text-center", "px-5 py-2 mt-2 dark:text-white text-center",
@ -186,59 +212,59 @@ export default function GenericNode({
) : ( ) : (
<></> <></>
)} */} )} */}
{data.node.template[t].show && {data.node.template[t].show &&
!data.node.template[t].advanced ? ( !data.node.template[t].advanced ? (
<ParameterComponent <ParameterComponent
data={data} data={data}
color={ color={
nodeColors[types[data.node.template[t].type]] ?? nodeColors[types[data.node.template[t].type]] ??
nodeColors.unknown nodeColors.unknown
} }
title={ title={
data.node.template[t].display_name data.node.template[t].display_name
? data.node.template[t].display_name ? data.node.template[t].display_name
: data.node.template[t].name : data.node.template[t].name
? toNormalCase(data.node.template[t].name) ? toNormalCase(data.node.template[t].name)
: toNormalCase(t) : toNormalCase(t)
} }
name={t} name={t}
tooltipTitle={ tooltipTitle={
"Type: " + "Type: " +
data.node.template[t].type + data.node.template[t].type +
(data.node.template[t].list ? " list" : "") (data.node.template[t].list ? " list" : "")
} }
required={data.node.template[t].required} required={data.node.template[t].required}
id={data.node.template[t].type + "|" + t + "|" + data.id} id={data.node.template[t].type + "|" + t + "|" + data.id}
left={true} left={true}
type={data.node.template[t].type} type={data.node.template[t].type}
/> />
) : ( ) : (
<></> <></>
)} )}
</div> </div>
))} ))}
<div <div
className={classNames( className={classNames(
Object.keys(data.node.template).length < 1 ? "hidden" : "", Object.keys(data.node.template).length < 1 ? "hidden" : "",
"w-full flex justify-center" "w-full flex justify-center"
)} )}
> >
{" "} {" "}
</div> </div>
{/* <div className="px-5 py-2 mt-2 dark:text-white text-center"> {/* <div className="px-5 py-2 mt-2 dark:text-white text-center">
Output Output
</div> */} </div> */}
<ParameterComponent <ParameterComponent
data={data} data={data}
color={nodeColors[types[data.type]] ?? nodeColors.unknown} color={nodeColors[types[data.type]] ?? nodeColors.unknown}
title={data.type} title={data.type}
tooltipTitle={`Type: ${data.node.base_classes.join(" | ")}`} tooltipTitle={`Type: ${data.node.base_classes.join(" | ")}`}
id={[data.type, data.id, ...data.node.base_classes].join("|")} id={[data.type, data.id, ...data.node.base_classes].join("|")}
type={data.node.base_classes.join("|")} type={data.node.base_classes.join("|")}
left={false} left={false}
/> />
</> </>
</div> </div>
</div> </div>
); );
} }