This commit is contained in:
Gabriel Almeida 2023-04-28 14:46:05 -03:00
commit 2bc1fdd32e
12 changed files with 454 additions and 399 deletions

View file

@ -1,8 +1,4 @@
import { import { useEffect, useRef, useState } from "react";
useEffect,
useRef,
useState,
} from "react";
import { ChatMessageType, ChatType } from "../../types/chat"; import { ChatMessageType, ChatType } from "../../types/chat";
import ChatTrigger from "./chatTrigger"; import ChatTrigger from "./chatTrigger";
@ -11,23 +7,26 @@ import ChatModal from "../../modals/chatModal";
const _ = require("lodash"); const _ = require("lodash");
export default function Chat({ flow }: ChatType) { export default function Chat({ flow }: ChatType) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
useEffect(() => { useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => { const handleKeyDown = (event: KeyboardEvent) => {
event.preventDefault() // event.preventDefault()
if ((event.key === "K"||event.key==="k") && (event.metaKey||event.ctrlKey)) { if (
setOpen(oldState=>!oldState); (event.key === "K" || event.key === "k") &&
} (event.metaKey || event.ctrlKey)
}; ) {
document.addEventListener("keydown", handleKeyDown); setOpen((oldState) => !oldState);
return () => { }
document.removeEventListener("keydown", handleKeyDown); };
}; document.addEventListener("keydown", handleKeyDown);
}, []); return () => {
return ( document.removeEventListener("keydown", handleKeyDown);
<> };
<ChatModal key={flow.id} flow={flow} open={open} setOpen={setOpen} /> }, []);
<ChatTrigger open={open} setOpen={setOpen} flow={flow} /> return (
</> <>
); <ChatModal key={flow.id} flow={flow} open={open} setOpen={setOpen} />
<ChatTrigger open={open} setOpen={setOpen} flow={flow} />
</>
);
} }

View file

@ -1,40 +1,43 @@
import { PromptTypeAPI, errorsTypeAPI } from './../../types/api/index'; import { PromptTypeAPI, errorsTypeAPI } from "./../../types/api/index";
import { APIObjectType, sendAllProps } from '../../types/api/index'; import { APIObjectType, sendAllProps } from "../../types/api/index";
import axios, { AxiosResponse } from "axios"; import axios, { AxiosResponse } from "axios";
import { FlowType } from '../../types/flow'; import { FlowType } from "../../types/flow";
export async function getAll():Promise<AxiosResponse<APIObjectType>> { export async function getAll(): Promise<AxiosResponse<APIObjectType>> {
return await axios.get(`/all`); return await axios.get(`/all`);
} }
export async function sendAll(data:sendAllProps) { export async function sendAll(data: sendAllProps) {
return await axios.post(`/predict`, data); return await axios.post(`/predict`, data);
} }
export async function checkCode(code:string):Promise<AxiosResponse<errorsTypeAPI>>{ export async function checkCode(
code: string
return await axios.post('/validate/code',{code}) ): Promise<AxiosResponse<errorsTypeAPI>> {
return await axios.post("/validate/code", { code });
} }
export async function checkPrompt(template:string):Promise<AxiosResponse<PromptTypeAPI>>{ export async function checkPrompt(
template: string
return await axios.post('/validate/prompt',{template}) ): Promise<AxiosResponse<PromptTypeAPI>> {
return await axios.post("/validate/prompt", { template });
} }
export async function getExamples(): Promise<FlowType[]> { export async function getExamples(): Promise<FlowType[]> {
const url = 'https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples'; const url =
const response = await axios.get(url); "https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples";
const response = await axios.get(url);
const jsonFiles = response.data.filter((file: any) => {
return file.name.endsWith('.json'); const jsonFiles = response.data.filter((file: any) => {
}); return file.name.endsWith(".json");
});
const contentsPromises = jsonFiles.map(async (file: any) => {
const contentResponse = await axios.get(file.download_url); const contentsPromises = jsonFiles.map(async (file: any) => {
return contentResponse.data; const contentResponse = await axios.get(file.download_url);
}); return contentResponse.data;
});
const contents = await Promise.all(contentsPromises);
const contents = await Promise.all(contentsPromises);
return contents;
} return contents;
}

View file

@ -1,15 +1,15 @@
import { useCallback, useContext, useEffect, useRef } from "react"; import { useCallback, useContext, useEffect, useRef } from "react";
import ReactFlow, { import ReactFlow, {
Background, Background,
Controls, Controls,
addEdge, addEdge,
useEdgesState, useEdgesState,
useNodesState, useNodesState,
useReactFlow, useReactFlow,
updateEdge, updateEdge,
EdgeChange, EdgeChange,
Connection, Connection,
Edge, Edge,
} from "reactflow"; } from "reactflow";
import { locationContext } from "../../contexts/locationContext"; import { locationContext } from "../../contexts/locationContext";
import ExtraSidebar from "./components/extraSidebarComponent"; import ExtraSidebar from "./components/extraSidebarComponent";
@ -24,193 +24,198 @@ import { APIClassType } from "../../types/api";
import { isValidConnection } from "../../utils"; import { isValidConnection } from "../../utils";
const nodeTypes = { const nodeTypes = {
genericNode: GenericNode, genericNode: GenericNode,
}; };
var _ = require("lodash"); var _ = require("lodash");
export default function FlowPage({ flow }:{flow:FlowType}) { export default function FlowPage({ flow }: { flow: FlowType }) {
let { updateFlow, incrementNodeId} = let { updateFlow, incrementNodeId } = useContext(TabsContext);
useContext(TabsContext); const { types, reactFlowInstance, setReactFlowInstance } =
const { types, reactFlowInstance, setReactFlowInstance } = useContext(typesContext);
useContext(typesContext); const reactFlowWrapper = useRef(null);
const reactFlowWrapper = useRef(null);
const { setExtraComponent, setExtraNavigation } = useContext(locationContext); const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
const [nodes, setNodes, onNodesChange] = useNodesState( const [nodes, setNodes, onNodesChange] = useNodesState(
flow.data?.nodes ?? [] flow.data?.nodes ?? []
); );
const [edges, setEdges, onEdgesChange] = useEdgesState( const [edges, setEdges, onEdgesChange] = useEdgesState(
flow.data?.edges ?? [] flow.data?.edges ?? []
); );
const { setViewport } = useReactFlow(); const { setViewport } = useReactFlow();
const edgeUpdateSuccessful = useRef(true) const edgeUpdateSuccessful = useRef(true);
useEffect(() => { useEffect(() => {
if (reactFlowInstance && flow) { if (reactFlowInstance && flow) {
flow.data = reactFlowInstance.toObject(); flow.data = reactFlowInstance.toObject();
updateFlow(flow); updateFlow(flow);
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [nodes, edges]); }, [nodes, edges]);
//update flow when tabs change //update flow when tabs change
useEffect(() => { useEffect(() => {
setNodes(flow?.data?.nodes ?? []); setNodes(flow?.data?.nodes ?? []);
setEdges(flow?.data?.edges ?? []); setEdges(flow?.data?.edges ?? []);
if (reactFlowInstance) { if (reactFlowInstance) {
setViewport(flow?.data?.viewport ?? { x: 1, y: 0, zoom: 0.5 }); setViewport(flow?.data?.viewport ?? { x: 1, y: 0, zoom: 0.5 });
} }
}, [flow, reactFlowInstance, setEdges, setNodes, setViewport]); }, [flow, reactFlowInstance, setEdges, setNodes, setViewport]);
//set extra sidebar //set extra sidebar
useEffect(() => { useEffect(() => {
setExtraComponent(<ExtraSidebar />); setExtraComponent(<ExtraSidebar />);
setExtraNavigation({ title: "Components" }); setExtraNavigation({ title: "Components" });
}, [setExtraComponent, setExtraNavigation]); }, [setExtraComponent, setExtraNavigation]);
const onEdgesChangeMod = useCallback( const onEdgesChangeMod = useCallback(
(s:EdgeChange[]) => { (s: EdgeChange[]) => {
onEdgesChange(s); onEdgesChange(s);
setNodes((x) => { setNodes((x) => {
let newX = _.cloneDeep(x); let newX = _.cloneDeep(x);
return newX; return newX;
}); });
}, },
[onEdgesChange, setNodes] [onEdgesChange, setNodes]
); );
const onConnect = useCallback( const onConnect = useCallback(
(params:Connection) => { (params: Connection) => {
setEdges((eds) => setEdges((eds) =>
addEdge({ ...params, className: "animate-pulse" }, eds) addEdge({ ...params, className: "animate-pulse" }, eds)
); );
setNodes((x) => { setNodes((x) => {
let newX = _.cloneDeep(x); let newX = _.cloneDeep(x);
return newX; return newX;
}); });
}, },
[setEdges, setNodes] [setEdges, setNodes]
); );
const onDragOver = useCallback((event:React.DragEvent) => { const onDragOver = useCallback((event: React.DragEvent) => {
event.preventDefault(); event.preventDefault();
event.dataTransfer.dropEffect = "move"; event.dataTransfer.dropEffect = "move";
}, []); }, []);
const onDrop = useCallback( const onDrop = useCallback(
(event:React.DragEvent) => { (event: React.DragEvent) => {
event.preventDefault(); event.preventDefault();
// Helper function to generate a unique node ID
function getId() {
return `dndnode_` + incrementNodeId();
}
// Get the current bounds of the ReactFlow wrapper element
const reactflowBounds = reactFlowWrapper.current.getBoundingClientRect();
// Extract the data from the drag event and parse it as a JSON object
let data:{type:string,node?:APIClassType} = JSON.parse(event.dataTransfer.getData("json"));
// If data type is not "chatInput" or if there are no "chatInputNode" nodes present in the ReactFlow instance, create a new node
if (
data.type !== "chatInput" ||
(data.type === "chatInput" &&
!reactFlowInstance.getNodes().some((n) => n.type === "chatInputNode"))
) {
// Calculate the position where the node should be created
const position = reactFlowInstance.project({
x: event.clientX - reactflowBounds.left,
y: event.clientY - reactflowBounds.top,
});
// Generate a unique node ID
let newId = getId();
// Create a new node object
const newNode:NodeType = {
id: newId,
type: "genericNode",
position,
data: {
...data,
id: newId,
value: null,
},
};
// Add the new node to the list of nodes in state
setNodes((nds) => nds.concat(newNode));
} else {
// If a chat input node already exists, set an error message
setErrorData({
title: "Error creating node",
list: ["There can't be more than one chat input."],
});
}
},
// Specify dependencies for useCallback
[incrementNodeId, reactFlowInstance, setErrorData, setNodes]
);
// Helper function to generate a unique node ID
const onDelete = (mynodes) => { function getId() {
setEdges(edges.filter((ns) => !nodes.some((n) => ns.source === n.id || ns.target === n.id))); return `dndnode_` + incrementNodeId();
} }
const onEdgeUpdateStart = useCallback(() => { // Get the current bounds of the ReactFlow wrapper element
edgeUpdateSuccessful.current = false; const reactflowBounds = reactFlowWrapper.current.getBoundingClientRect();
}, []);
// Extract the data from the drag event and parse it as a JSON object
const onEdgeUpdate = useCallback((oldEdge:Edge, newConnection:Connection) => { let data: { type: string; node?: APIClassType } = JSON.parse(
if(isValidConnection(newConnection,reactFlowInstance)){ event.dataTransfer.getData("json")
edgeUpdateSuccessful.current = true; );
setEdges((els) => updateEdge(oldEdge, newConnection, els));
}
}, []);
const onEdgeUpdateEnd = useCallback((_, edge) => { // If data type is not "chatInput" or if there are no "chatInputNode" nodes present in the ReactFlow instance, create a new node
if (!edgeUpdateSuccessful.current) { if (
setEdges((eds) => eds.filter((e) => e.id !== edge.id)); data.type !== "chatInput" ||
} (data.type === "chatInput" &&
!reactFlowInstance.getNodes().some((n) => n.type === "chatInputNode"))
edgeUpdateSuccessful.current = true; ) {
}, []); // Calculate the position where the node should be created
const position = reactFlowInstance.project({
return ( x: event.clientX - reactflowBounds.left,
<div className="w-full h-full" ref={reactFlowWrapper}> y: event.clientY - reactflowBounds.top,
{Object.keys(types).length > 0 ? ( });
<>
<ReactFlow // Generate a unique node ID
nodes={nodes} let newId = getId();
onMove={() =>
updateFlow({ ...flow, data: reactFlowInstance.toObject() }) // Create a new node object
} const newNode: NodeType = {
edges={edges} id: newId,
onNodesChange={onNodesChange} type: "genericNode",
onEdgesChange={onEdgesChangeMod} position,
onConnect={onConnect} data: {
onLoad={setReactFlowInstance} ...data,
onInit={setReactFlowInstance} id: newId,
nodeTypes={nodeTypes} value: null,
onEdgeUpdate={onEdgeUpdate} },
onEdgeUpdateStart={onEdgeUpdateStart} };
onEdgeUpdateEnd={onEdgeUpdateEnd}
connectionLineComponent={ConnectionLineComponent} // Add the new node to the list of nodes in state
onDragOver={onDragOver} setNodes((nds) => nds.concat(newNode));
onDrop={onDrop} } else {
onNodesDelete={onDelete} // If a chat input node already exists, set an error message
> setErrorData({
<Background className="dark:bg-gray-900"/> title: "Error creating node",
<Controls className="[&>button]:text-black [&>button]:dark:bg-gray-800 hover:[&>button]:dark:bg-gray-700 [&>button]:dark:text-gray-400 [&>button]:dark:fill-gray-400 [&>button]:dark:border-gray-600"> list: ["There can't be more than one chat input."],
</Controls> });
</ReactFlow> }
<Chat flow={flow} reactFlowInstance={reactFlowInstance} /> },
</> // Specify dependencies for useCallback
) : ( [incrementNodeId, reactFlowInstance, setErrorData, setNodes]
<></> );
)}
</div> const onDelete = (mynodes) => {
); setEdges(
edges.filter(
(ns) => !nodes.some((n) => ns.source === n.id || ns.target === n.id)
)
);
};
const onEdgeUpdateStart = useCallback(() => {
edgeUpdateSuccessful.current = false;
}, []);
const onEdgeUpdate = useCallback(
(oldEdge: Edge, newConnection: Connection) => {
if (isValidConnection(newConnection, reactFlowInstance)) {
edgeUpdateSuccessful.current = true;
setEdges((els) => updateEdge(oldEdge, newConnection, els));
}
},
[]
);
const onEdgeUpdateEnd = useCallback((_, edge) => {
if (!edgeUpdateSuccessful.current) {
setEdges((eds) => eds.filter((e) => e.id !== edge.id));
}
edgeUpdateSuccessful.current = true;
}, []);
return (
<div className="w-full h-full" ref={reactFlowWrapper}>
{Object.keys(types).length > 0 ? (
<>
<ReactFlow
nodes={nodes}
onMove={() =>
updateFlow({ ...flow, data: reactFlowInstance.toObject() })
}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChangeMod}
onConnect={onConnect}
onLoad={setReactFlowInstance}
onInit={setReactFlowInstance}
nodeTypes={nodeTypes}
onEdgeUpdate={onEdgeUpdate}
onEdgeUpdateStart={onEdgeUpdateStart}
onEdgeUpdateEnd={onEdgeUpdateEnd}
connectionLineComponent={ConnectionLineComponent}
onDragOver={onDragOver}
onDrop={onDrop}
onNodesDelete={onDelete}
>
<Background className="dark:bg-gray-900" />
<Controls className="[&>button]:text-black [&>button]:dark:bg-gray-800 hover:[&>button]:dark:bg-gray-700 [&>button]:dark:text-gray-400 [&>button]:dark:fill-gray-400 [&>button]:dark:border-gray-600"></Controls>
</ReactFlow>
<Chat flow={flow} reactFlowInstance={reactFlowInstance} />
</>
) : (
<></>
)}
</div>
);
} }

View file

@ -1,8 +1,8 @@
import { ReportHandler } from 'web-vitals'; import { ReportHandler } from "web-vitals";
const reportWebVitals = (onPerfEntry?: ReportHandler) => { const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) { if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry); getCLS(onPerfEntry);
getFID(onPerfEntry); getFID(onPerfEntry);
getFCP(onPerfEntry); getFCP(onPerfEntry);

View file

@ -1,5 +1,4 @@
declare module '*.svg' { declare module "*.svg" {
const content: any; const content: any;
export default content; export default content;
} }

View file

@ -1,20 +1,40 @@
import { Node,Edge,Viewport } from "reactflow" import { Node, Edge, Viewport } from "reactflow";
//kind and class are just representative names to represent the actual structure of the object received by the API //kind and class are just representative names to represent the actual structure of the object received by the API
export type APIObjectType = {kind:APIKindType,[key:string]:APIKindType} export type APIObjectType = { kind: APIKindType; [key: string]: APIKindType };
export type APIKindType= {class:APIClassType,[key:string]:APIClassType} export type APIKindType = { class: APIClassType; [key: string]: APIClassType };
export type APITemplateType = {variable:TemplateVariableType,[key:string]:TemplateVariableType} export type APITemplateType = {
export type APIClassType ={base_classes:Array<string>,description:string,template:APITemplateType,[key:string]:Array<string>|string|APITemplateType} variable: TemplateVariableType;
export type TemplateVariableType = {type:string,required:boolean,placeholder?:string,list:boolean,show:boolean,multiline?:boolean,value?:any,[key:string]:any} [key: string]: TemplateVariableType;
export type sendAllProps={
nodes: Node[];
edges: Edge[];
name:string,
description:string;
viewport: Viewport;
message:string;
chatHistory:{message:string,isSend:boolean}[],
}; };
export type errorsTypeAPI={function:{errors:Array<string>},imports:{errors:Array<string>}} export type APIClassType = {
export type PromptTypeAPI = {input_variables:Array<string>} base_classes: Array<string>;
description: string;
template: APITemplateType;
[key: string]: Array<string> | string | APITemplateType;
};
export type TemplateVariableType = {
type: string;
required: boolean;
placeholder?: string;
list: boolean;
show: boolean;
multiline?: boolean;
value?: any;
[key: string]: any;
};
export type sendAllProps = {
nodes: Node[];
edges: Edge[];
name: string;
description: string;
viewport: Viewport;
message: string;
chatHistory: { message: string; isSend: boolean }[];
};
export type errorsTypeAPI = {
function: { errors: Array<string> };
imports: { errors: Array<string> };
};
export type PromptTypeAPI = { input_variables: Array<string> };

View file

@ -1,81 +1,85 @@
import { ForwardRefExoticComponent, ReactElement, ReactNode } from "react"; import { ForwardRefExoticComponent, ReactElement, ReactNode } from "react";
import { NodeDataType } from "../flow/index"; import { NodeDataType } from "../flow/index";
export type InputComponentType = { export type InputComponentType = {
value: string; value: string;
disabled?: boolean; disabled?: boolean;
onChange: (value: string) => void; onChange: (value: string) => void;
password: boolean; password: boolean;
}; };
export type ToggleComponentType = { export type ToggleComponentType = {
enabled: boolean; enabled: boolean;
setEnabled: (state: boolean) => void; setEnabled: (state: boolean) => void;
disabled: boolean; disabled: boolean;
}; };
export type DropDownComponentType = { export type DropDownComponentType = {
value: string; value: string;
options: string[]; options: string[];
onSelect: (value: string) => void; onSelect: (value: string) => void;
}; };
export type ParameterComponentType = { export type ParameterComponentType = {
data: NodeDataType; data: NodeDataType;
title: string; title: string;
id: string; id: string;
color: string; color: string;
left: boolean; left: boolean;
type: string; type: string;
required?: boolean; required?: boolean;
name?: string; name?: string;
tooltipTitle: string; tooltipTitle: string;
}; };
export type InputListComponentType = { export type InputListComponentType = {
value: string[]; value: string[];
onChange: (value: string[]) => void; onChange: (value: string[]) => void;
disabled: boolean; disabled: boolean;
}; };
export type TextAreaComponentType = { export type TextAreaComponentType = {
disabled: boolean; disabled: boolean;
onChange: (value: string[] | string) => void; onChange: (value: string[] | string) => void;
value: string; value: string;
}; };
export type FileComponentType = { export type FileComponentType = {
disabled: boolean; disabled: boolean;
onChange: (value: string[] | string) => void; onChange: (value: string[] | string) => void;
value: string; value: string;
suffixes:Array<string>; suffixes: Array<string>;
fileTypes:Array<string>; fileTypes: Array<string>;
onFileChange:(value: string) => void; onFileChange: (value: string) => void;
}; };
export type DisclosureComponentType = { export type DisclosureComponentType = {
children: ReactNode; children: ReactNode;
button: { button: {
title: string; title: string;
Icon: ForwardRefExoticComponent<React.SVGProps<SVGSVGElement>>; Icon: ForwardRefExoticComponent<React.SVGProps<SVGSVGElement>>;
buttons?: { buttons?: {
Icon: ReactElement; Icon: ReactElement;
title: string; title: string;
onClick: (event?: React.MouseEvent) => void; onClick: (event?: React.MouseEvent) => void;
}[]; }[];
}; };
}; };
export type FloatComponentType = { export type FloatComponentType = {
value: string; value: string;
disabled?: boolean; disabled?: boolean;
onChange: (value: string) => void; onChange: (value: string) => void;
}; };
export type TooltipComponentType={children:ReactElement,title:string,placement?: export type TooltipComponentType = {
| 'bottom-end' children: ReactElement;
| 'bottom-start' title: string;
| 'bottom' placement?:
| 'left-end' | "bottom-end"
| 'left-start' | "bottom-start"
| 'left' | "bottom"
| 'right-end' | "left-end"
| 'right-start' | "left-start"
| 'right' | "left"
| 'top-end' | "right-end"
| 'top-start' | "right-start"
| 'top';} | "right"
| "top-end"
| "top-start"
| "top";
};

View file

@ -1,3 +1,8 @@
import { HomeIcon } from "@heroicons/react/24/outline"; import { HomeIcon } from "@heroicons/react/24/outline";
export type sidebarNavigationItemType = { name: string, href: string, icon: React.ForwardRefExoticComponent<React.SVGProps<SVGSVGElement>>, current: boolean } export type sidebarNavigationItemType = {
name: string;
href: string;
icon: React.ForwardRefExoticComponent<React.SVGProps<SVGSVGElement>>;
current: boolean;
};

View file

@ -1,12 +1,22 @@
import { ChatMessageType } from './../chat/index'; import { ChatMessageType } from "./../chat/index";
import { APIClassType } from '../api/index'; import { APIClassType } from "../api/index";
import { ReactFlowJsonObject, XYPosition } from "reactflow"; import { ReactFlowJsonObject, XYPosition } from "reactflow";
export type FlowType = { export type FlowType = {
name: string; name: string;
id: string; id: string;
data: ReactFlowJsonObject; data: ReactFlowJsonObject;
description:string; description: string;
};
export type NodeType = {
id: string;
type?: string;
position: XYPosition;
data: NodeDataType;
};
export type NodeDataType = {
type: string;
node?: APIClassType;
id: string;
value: any;
}; };
export type NodeType = {id:string,type:string,position:XYPosition,data:NodeDataType}
export type NodeDataType = {type:string,node?:APIClassType,id:string,value:any}

View file

@ -1,15 +1,15 @@
import { FlowType } from "../flow"; import { FlowType } from "../flow";
export type TabsContextType = { export type TabsContextType = {
save:()=>void; save: () => void;
tabIndex: number; tabIndex: number;
setTabIndex: (index: number) => void; setTabIndex: (index: number) => void;
flows: Array<FlowType>; flows: Array<FlowType>;
removeFlow: (id: string) => void; removeFlow: (id: string) => void;
addFlow: (flowData?: FlowType) => void; addFlow: (flowData?: FlowType) => void;
updateFlow: (newFlow: FlowType) => void; updateFlow: (newFlow: FlowType) => void;
incrementNodeId: () => number; incrementNodeId: () => number;
downloadFlow: (flow:FlowType) => void; downloadFlow: (flow: FlowType) => void;
uploadFlow: () => void; uploadFlow: () => void;
hardReset:()=>void; hardReset: () => void;
}; };

View file

@ -1,11 +1,11 @@
import { ReactFlowInstance } from "reactflow"; import { ReactFlowInstance } from "reactflow";
const types:{[char: string]: string}={} const types: { [char: string]: string } = {};
export type typesContextType = { export type typesContextType = {
reactFlowInstance: ReactFlowInstance|null; reactFlowInstance: ReactFlowInstance | null;
setReactFlowInstance: any; setReactFlowInstance: any;
deleteNode: (idx: string) => void; deleteNode: (idx: string) => void;
types: typeof types; types: typeof types;
setTypes: (newState: {}) => void; setTypes: (newState: {}) => void;
}; };

View file

@ -14,13 +14,13 @@ import {
FingerPrintIcon, FingerPrintIcon,
ScissorsIcon, ScissorsIcon,
CircleStackIcon, CircleStackIcon,
Squares2X2Icon Squares2X2Icon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { Connection, Edge, Node, ReactFlowInstance } from "reactflow"; import { Connection, Edge, Node, ReactFlowInstance } from "reactflow";
import { FlowType } from "./types/flow"; import { FlowType } from "./types/flow";
var _ = require('lodash') var _ = require("lodash");
export function classNames(...classes:Array<string>) { export function classNames(...classes: Array<string>) {
return classes.filter(Boolean).join(" "); return classes.filter(Boolean).join(" ");
} }
@ -70,7 +70,7 @@ export const borderLColors = {
gray: "border-l-gray-500", gray: "border-l-gray-500",
}; };
export const nodeColors: {[char: string]: string} = { export const nodeColors: { [char: string]: string } = {
prompts: "#4367BF", prompts: "#4367BF",
llms: "#6344BE", llms: "#6344BE",
chains: "#FE7500", chains: "#FE7500",
@ -79,18 +79,18 @@ export const nodeColors: {[char: string]: string} = {
memories: "#F5B85A", memories: "#F5B85A",
advanced: "#000000", advanced: "#000000",
chat: "#198BF6", chat: "#198BF6",
thought:"#272541", thought: "#272541",
embeddings:"#42BAA7", embeddings: "#42BAA7",
documentloaders:"#7AAE42", documentloaders: "#7AAE42",
vectorstores: "#AA8742", vectorstores: "#AA8742",
textsplitters: "#B47CB5", textsplitters: "#B47CB5",
toolkits:"#DB2C2C", toolkits: "#DB2C2C",
wrappers:"#E6277A", wrappers: "#E6277A",
utilities:"#31A3CC", utilities: "#31A3CC",
unknown:"#9CA3AF" unknown: "#9CA3AF",
}; };
export const nodeNames:{[char: string]: string} = { export const nodeNames: { [char: string]: string } = {
prompts: "Prompts", prompts: "Prompts",
llms: "LLMs", llms: "LLMs",
chains: "Chains", chains: "Chains",
@ -102,14 +102,18 @@ export const nodeNames:{[char: string]: string} = {
embeddings: "Embeddings", embeddings: "Embeddings",
documentloaders: "Document Loaders", documentloaders: "Document Loaders",
vectorstores: "Vector Stores", vectorstores: "Vector Stores",
toolkits:"Toolkits", toolkits: "Toolkits",
wrappers:"Wrappers", wrappers: "Wrappers",
textsplitters: "Text Splitters", textsplitters: "Text Splitters",
utilities:"Utilities", utilities: "Utilities",
unknown:"Unknown" unknown: "Unknown",
}; };
export const nodeIcons:{[char: string]: React.ForwardRefExoticComponent<React.SVGProps<SVGSVGElement>>} = { export const nodeIcons: {
[char: string]: React.ForwardRefExoticComponent<
React.SVGProps<SVGSVGElement>
>;
} = {
agents: RocketLaunchIcon, agents: RocketLaunchIcon,
chains: LinkIcon, chains: LinkIcon,
memories: CpuChipIcon, memories: CpuChipIcon,
@ -118,14 +122,14 @@ export const nodeIcons:{[char: string]: React.ForwardRefExoticComponent<React.SV
tools: WrenchIcon, tools: WrenchIcon,
advanced: ComputerDesktopIcon, advanced: ComputerDesktopIcon,
chat: Bars3CenterLeftIcon, chat: Bars3CenterLeftIcon,
embeddings:FingerPrintIcon, embeddings: FingerPrintIcon,
documentloaders:PaperClipIcon, documentloaders: PaperClipIcon,
vectorstores: CircleStackIcon, vectorstores: CircleStackIcon,
toolkits:WrenchScrewdriverIcon, toolkits: WrenchScrewdriverIcon,
textsplitters:ScissorsIcon, textsplitters: ScissorsIcon,
wrappers:GiftIcon, wrappers: GiftIcon,
utilities:Squares2X2Icon, utilities: Squares2X2Icon,
unknown:QuestionMarkCircleIcon unknown: QuestionMarkCircleIcon,
}; };
export const bgColors = { export const bgColors = {
@ -218,7 +222,7 @@ export const taskTypeMap: { [key: string]: string } = {
MULTICLASS_CLASSIFICATION: "Multiclass Classification", MULTICLASS_CLASSIFICATION: "Multiclass Classification",
}; };
const charWidths:{[char: string]: number} = { const charWidths: { [char: string]: number } = {
" ": 0.2, " ": 0.2,
"!": 0.2, "!": 0.2,
'"': 0.3, '"': 0.3,
@ -260,7 +264,7 @@ for (let i = 97; i <= 122; i++) {
charWidths[String.fromCharCode(i)] = 0.5; charWidths[String.fromCharCode(i)] = 0.5;
} }
export function measureTextWidth(text: string, fontSize:number) { export function measureTextWidth(text: string, fontSize: number) {
let wordWidth = 0; let wordWidth = 0;
for (let j = 0; j < text.length; j++) { for (let j = 0; j < text.length; j++) {
let char = text[j]; let char = text[j];
@ -270,7 +274,11 @@ export function measureTextWidth(text: string, fontSize:number) {
return wordWidth; return wordWidth;
} }
export function measureTextHeight(text: string, width:number, fontSize:number) { export function measureTextHeight(
text: string,
width: number,
fontSize: number
) {
const charHeight = fontSize; const charHeight = fontSize;
const lineHeight = charHeight * 1.5; const lineHeight = charHeight * 1.5;
const words = text.split(" "); const words = text.split(" ");
@ -319,19 +327,19 @@ export function snakeToNormalCase(str: string) {
.join(" "); .join(" ");
} }
export function normalCaseToSnakeCase(str:string){ export function normalCaseToSnakeCase(str: string) {
return str return str
.split(" ") .split(" ")
.map((word, index) => { .map((word, index) => {
if (index === 0) { if (index === 0) {
return word[0].toUpperCase() + word.slice(1).toLowerCase(); return word[0].toUpperCase() + word.slice(1).toLowerCase();
} }
return word.toLowerCase(); return word.toLowerCase();
}) })
.join("_"); .join("_");
} }
export function roundNumber(x:number, decimals:number) { export function roundNumber(x: number, decimals: number) {
return Math.round(x * Math.pow(10, decimals)) / Math.pow(10, decimals); return Math.round(x * Math.pow(10, decimals)) / Math.pow(10, decimals);
} }
@ -345,12 +353,15 @@ export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
} }
export function isValidConnection( export function isValidConnection(
{ source, target, sourceHandle, targetHandle }:Connection, { source, target, sourceHandle, targetHandle }: Connection,
reactFlowInstance:ReactFlowInstance reactFlowInstance: ReactFlowInstance
) { ) {
if ( if (
sourceHandle.split('|')[0] === targetHandle.split("|")[0] || sourceHandle.split("|")[0] === targetHandle.split("|")[0] ||
sourceHandle.split('|').slice(2).some((t) => t === targetHandle.split("|")[0]) || sourceHandle
.split("|")
.slice(2)
.some((t) => t === targetHandle.split("|")[0]) ||
targetHandle.split("|")[0] === "str" targetHandle.split("|")[0] === "str"
) { ) {
let targetNode = reactFlowInstance.getNode(target).data.node; let targetNode = reactFlowInstance.getNode(target).data.node;
@ -375,16 +386,15 @@ export function isValidConnection(
return false; return false;
} }
export function removeApiKeys(flow:FlowType):FlowType{ export function removeApiKeys(flow: FlowType): FlowType {
let cleanFLow = _.cloneDeep(flow) let cleanFLow = _.cloneDeep(flow);
cleanFLow.data.nodes.forEach(node=>{ cleanFLow.data.nodes.forEach((node) => {
for(const key in node.data.node.template) for (const key in node.data.node.template) {
{ if (key.includes("api")) {
if(key.includes('api')){ console.log(node.data.node.template[key]);
console.log(node.data.node.template[key]) node.data.node.template[key].value = "";
node.data.node.template[key].value = ''
} }
} }
}) });
return cleanFLow return cleanFLow;
} }