Merge branch '45-implement-agents-as-tools' of https://github.com/logspace-ai/langflow into 45-implement-agents-as-tools

This commit is contained in:
Gabriel Almeida 2023-03-28 19:18:43 -03:00
commit c5c42a37f2
25 changed files with 918 additions and 177 deletions

View file

@ -21,10 +21,14 @@
"@types/node": "^16.18.12",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"ace-builds": "^1.16.0",
"axios": "^1.3.2",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-cookie": "^4.1.1",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.2",
"react-icons": "^4.7.1",
"react-laag": "^2.0.5",
"react-router-dom": "^6.8.1",
@ -5096,6 +5100,11 @@
"node": ">= 0.6"
}
},
"node_modules/ace-builds": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.16.0.tgz",
"integrity": "sha512-EriMhoxdfhh0zKm7icSt8EXekODAOVsYh9fpnlru9ALwf0Iw7J7bpuqLjhi3QRxvVKR7P0teQdJwTvjVMcYHuw=="
},
"node_modules/acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
@ -7203,6 +7212,11 @@
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
},
"node_modules/diff-match-patch": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
"integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
},
"node_modules/diff-sequences": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
@ -12407,6 +12421,16 @@
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
},
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@ -14801,6 +14825,22 @@
"node": ">=0.10.0"
}
},
"node_modules/react-ace": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/react-ace/-/react-ace-10.1.0.tgz",
"integrity": "sha512-VkvUjZNhdYTuKOKQpMIZi7uzZZVgzCjM7cLYu6F64V0mejY8a2XTyPUIMszC6A4trbeMIHbK5fYFcT/wkP/8VA==",
"dependencies": {
"ace-builds": "^1.4.14",
"diff-match-patch": "^1.0.5",
"lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0",
"prop-types": "^15.7.2"
},
"peerDependencies": {
"react": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-app-polyfill": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz",
@ -14959,6 +14999,17 @@
"react": "^18.2.0"
}
},
"node_modules/react-error-boundary": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.2.tgz",
"integrity": "sha512-/h21OS80hQ1m/s5UVOp1JKkC8XmUo0rOTRUliGSmWtvswkbbijuQ074K0QLEHwxwwesTt7ksR74/9EHImqWo+A==",
"dependencies": {
"@babel/runtime": "^7.12.5"
},
"peerDependencies": {
"react": ">=16.13.1"
}
},
"node_modules/react-error-overlay": {
"version": "6.0.11",
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",

View file

@ -16,10 +16,14 @@
"@types/node": "^16.18.12",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"ace-builds": "^1.16.0",
"axios": "^1.3.2",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-cookie": "^4.1.1",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.2",
"react-icons": "^4.7.1",
"react-laag": "^2.0.5",
"react-router-dom": "^6.8.1",
@ -54,5 +58,5 @@
"last 1 safari version"
]
},
"proxy": "http://localhost:7860"
"proxy": "http://backend:7860"
}

View file

@ -9,6 +9,9 @@ import ExtraSidebar from "./components/ExtraSidebarComponent";
import { alertContext } from "./contexts/alertContext";
import { locationContext } from "./contexts/locationContext";
import TabsManagerComponent from "./pages/FlowPage/components/tabsManagerComponent";
import { ErrorBoundary } from "react-error-boundary";
import CrashErrorComponent from "./components/CrashErrorComponent";
import { TabsContext } from "./contexts/tabsContext";
export default function App() {
var _ = require("lodash");
@ -21,7 +24,7 @@ export default function App() {
setShowSideBar(true);
setIsStackedOpen(true);
}, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]);
const {hardReset} = useContext(TabsContext)
const {
errorData,
errorOpen,
@ -34,45 +37,62 @@ export default function App() {
setSuccessOpen,
} = useContext(alertContext);
// Initialize state variable for the list of alerts
const [alertsList, setAlertsList] = useState<Array<{type:string,data:{title:string,list?:Array<string>,link?:string},id:string}>>([]);
// Initialize state variable for the list of alerts
const [alertsList, setAlertsList] = useState<
Array<{
type: string;
data: { title: string; list?: Array<string>; link?: string };
id: string;
}>
>([]);
// Use effect hook to update alertsList when a new alert is added
useEffect(() => {
// If there is an error alert open with data, add it to the alertsList
if (errorOpen && errorData) {
setErrorOpen(false);
setAlertsList((old) => {
let newAlertsList = [
...old,
{ type: "error", data: _.cloneDeep(errorData), id: _.uniqueId() },
];
return newAlertsList;
});
}
// If there is a notice alert open with data, add it to the alertsList
else if (noticeOpen && noticeData) {
setNoticeOpen(false);
setAlertsList((old) => {
let newAlertsList = [
...old,
{ type: "notice", data: _.cloneDeep(noticeData), id: _.uniqueId() },
];
return newAlertsList;
});
}
// If there is a success alert open with data, add it to the alertsList
else if (successOpen && successData) {
setSuccessOpen(false);
setAlertsList((old) => {
let newAlertsList = [
...old,
{ type: "success", data: _.cloneDeep(successData), id: _.uniqueId() },
];
return newAlertsList;
});
}
}, [_, errorData, errorOpen, noticeData, noticeOpen, setErrorOpen, setNoticeOpen, setSuccessOpen, successData, successOpen]);
// Use effect hook to update alertsList when a new alert is added
useEffect(() => {
// If there is an error alert open with data, add it to the alertsList
if (errorOpen && errorData) {
setErrorOpen(false);
setAlertsList((old) => {
let newAlertsList = [
...old,
{ type: "error", data: _.cloneDeep(errorData), id: _.uniqueId() },
];
return newAlertsList;
});
}
// If there is a notice alert open with data, add it to the alertsList
else if (noticeOpen && noticeData) {
setNoticeOpen(false);
setAlertsList((old) => {
let newAlertsList = [
...old,
{ type: "notice", data: _.cloneDeep(noticeData), id: _.uniqueId() },
];
return newAlertsList;
});
}
// If there is a success alert open with data, add it to the alertsList
else if (successOpen && successData) {
setSuccessOpen(false);
setAlertsList((old) => {
let newAlertsList = [
...old,
{ type: "success", data: _.cloneDeep(successData), id: _.uniqueId() },
];
return newAlertsList;
});
}
}, [
_,
errorData,
errorOpen,
noticeData,
noticeOpen,
setErrorOpen,
setNoticeOpen,
setSuccessOpen,
successData,
successOpen,
]);
const removeAlert = (id: string) => {
setAlertsList((prevAlertsList) =>
@ -83,18 +103,27 @@ useEffect(() => {
return (
//need parent component with width and height
<div className="h-full flex flex-col">
<div className="flex grow-0 shrink basis-auto">
</div>
<div className="flex grow shrink basis-auto min-h-0 flex-1 overflow-hidden">
<ExtraSidebar />
{/* Main area */}
<main className="min-w-0 flex-1 border-t border-gray-200 dark:border-gray-700 flex">
{/* Primary column */}
<div className="w-full h-full">
<TabsManagerComponent></TabsManagerComponent>
</div>
</main>
</div>
<div className="flex grow-0 shrink basis-auto"></div>
<ErrorBoundary
onReset={() => {
window.localStorage.removeItem("tabsData");
window.localStorage.clear();
hardReset()
window.location.href = window.location.href;
}}
FallbackComponent={CrashErrorComponent}
>
<div className="flex grow shrink basis-auto min-h-0 flex-1 overflow-hidden">
<ExtraSidebar />
{/* Main area */}
<main className="min-w-0 flex-1 border-t border-gray-200 dark:border-gray-700 flex">
{/* Primary column */}
<div className="w-full h-full">
<TabsManagerComponent></TabsManagerComponent>
</div>
</main>
</div>
</ErrorBoundary>
<div></div>
<div className="flex z-40 flex-col-reverse fixed bottom-5 left-5">
{alertsList.map((alert) => (
@ -126,7 +155,13 @@ useEffect(() => {
</div>
))}
</div>
<a target={"_blank"} href="https://logspace.ai/" className="absolute bottom-1 left-1 text-gray-500 text-xs cursor-pointer font-sans tracking-wide">Created by Logspace</a>
<a
target={"_blank"}
href="https://logspace.ai/"
className="absolute bottom-1 left-1 text-gray-500 text-xs cursor-pointer font-sans tracking-wide"
>
Created by Logspace
</a>
</div>
);
}

View file

@ -10,6 +10,7 @@ import { typesContext } from "../../../../contexts/typesContext";
import { ParameterComponentType } from "../../../../types/components";
import FloatComponent from "../../../../components/floatComponent";
import Dropdown from "../../../../components/dropdownComponent";
import CodeAreaComponent from "../../../../components/codeAreaComponent";
export default function ParameterComponent({
left,
@ -136,9 +137,17 @@ export default function ParameterComponent({
data.node.template[name].options ? (
<Dropdown
options={data.node.template[name].options}
onSelect={(newValue) => data.node.template[name].value=newValue}
value={data.node.template[name].value??"chose an option"}
onSelect={(newValue) => (data.node.template[name].value = newValue)}
value={data.node.template[name].value ?? "chose an option"}
></Dropdown>
) : left === true && type === "code" ? (
<CodeAreaComponent
disabled={disabled}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
}}
/>
) : (
<></>
)}

View file

@ -1,92 +1,121 @@
import { TrashIcon } from "@heroicons/react/24/outline";
import {
TrashIcon,
} from "@heroicons/react/24/outline";
import {
classNames,
nodeColors,
nodeIcons,
snakeToNormalCase,
classNames,
nodeColors,
nodeIcons,
snakeToNormalCase,
} from "../../utils";
import ParameterComponent from "./components/parameterComponent";
import { typesContext } from "../../contexts/typesContext";
import { useContext } from "react";
import { NodeDataType} from "../../types/flow";
import { useContext, useRef } from "react";
import { NodeDataType } from "../../types/flow";
import { alertContext } from "../../contexts/alertContext";
export default function GenericNode({ data, selected}:{data:NodeDataType,selected:boolean}) {
const {types, deleteNode} = useContext(typesContext);
const Icon = nodeIcons[types[data.type]];
export default function GenericNode({
data,
selected,
}: {
data: NodeDataType;
selected: boolean;
}) {
const { setErrorData } = useContext(alertContext);
const showError = useRef(true);
const { types, deleteNode } = useContext(typesContext);
const Icon = nodeIcons[types[data.type]];
if (!Icon) {
console.log(data);
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;
}
return;
}
console.log(data)
return (
<div
className={classNames(
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"
)}
>
<div className="w-full dark:text-white flex items-center justify-between p-4 gap-8 bg-gray-50 rounded-t-lg dark:bg-gray-800 border-b dark:border-b-gray-700 ">
<div className="w-full flex items-center truncate gap-4 text-lg">
<Icon
className="w-10 h-10 p-1 rounded"
style={{
color: nodeColors[types[data.type]] ?? nodeColors.unknown,
}}
/>
<div className="truncate">{data.type}</div>
</div>
<button
onClick={() => {
deleteNode(data.id);
}}
>
<TrashIcon className="w-6 h-6 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-500"></TrashIcon>
</button>
</div>
<div className="w-full h-full py-5">
<div className="w-full text-gray-500 px-5 text-sm">
{data.node.description}
</div>
return (
<div className={ classNames(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")}>
<div className="w-full dark:text-white flex items-center justify-between p-4 gap-8 bg-gray-50 rounded-t-lg dark:bg-gray-800 border-b dark:border-b-gray-700 ">
<div className="w-full flex items-center truncate gap-4 text-lg">
<Icon
className="w-10 h-10 p-1 rounded"
style={{ color: nodeColors[types[data.type]] }}
/>
<div className="truncate">{data.type}</div>
</div>
<button onClick={() => {deleteNode(data.id)}}>
<TrashIcon className="w-6 h-6 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-500"></TrashIcon>
</button>
</div>
<div className="w-full h-full py-5">
<div className="w-full text-gray-500 px-5 text-sm">
{data.node.description}
</div>
<>
{Object.keys(data.node.template)
.filter((t) => t.charAt(0) !== "_")
.map((t:string, idx) => (
<div key={idx}>
{idx === 0 ? (
<div className="px-5 py-2 mt-2 dark:text-white text-center">Inputs:</div>
) : (
<></>
)}
{data.node.template[t].show ? (
<ParameterComponent
data={data}
color={
nodeColors[types[data.node.template[t].type]] ??
nodeColors[types[data.node.template[t].type]] ??
"black"
}
title={
snakeToNormalCase(t)
}
name={t}
tooltipTitle={
"Type: " +
data.node.template[t].type +
(data.node.template[t].list ? " list" : "")
}
required={data.node.template[t].required}
id={data.node.template[t].type + "|" + t + "|" + data.id}
left={true}
type={data.node.template[t].type}
/>
) : (
<></>
)}
</div>
))}
<div className="px-5 py-2 mt-2 dark:text-white text-center">Output:</div>
<ParameterComponent
data={data}
color={nodeColors[types[data.type]]}
title={data.type}
tooltipTitle={`Type: ${data.node.base_classes.join(' | ')}`}
id={[data.type, data.id, ...data.node.base_classes].join('|')}
type={'str'}
left={false}
/>
</>
</div>
</div>
);
<>
{Object.keys(data.node.template)
.filter((t) => t.charAt(0) !== "_")
.map((t: string, idx) => (
<div key={idx}>
{idx === 0 ? (
<div className="px-5 py-2 mt-2 dark:text-white text-center">
Inputs:
</div>
) : (
<></>
)}
{data.node.template[t].show ? (
<ParameterComponent
data={data}
color={
nodeColors[types[data.node.template[t].type]] ??
nodeColors.unknown
}
title={snakeToNormalCase(t)}
name={t}
tooltipTitle={
"Type: " +
data.node.template[t].type +
(data.node.template[t].list ? " list" : "")
}
required={data.node.template[t].required}
id={data.node.template[t].type + "|" + t + "|" + data.id}
left={true}
type={data.node.template[t].type}
/>
) : (
<></>
)}
</div>
))}
<div className="px-5 py-2 mt-2 dark:text-white text-center">
Output:
</div>
<ParameterComponent
data={data}
color={nodeColors[types[data.type]] ?? nodeColors.unknown}
title={data.type}
tooltipTitle={`Type: ${data.node.base_classes.join(" | ")}`}
id={[data.type, data.id, ...data.node.base_classes].join("|")}
type={"str"}
left={false}
/>
</>
</div>
</div>
);
}

View file

@ -0,0 +1,31 @@
export default function CrashErrorComponent({ error, resetErrorBoundary }) {
return (
<div className="fixed top-0 left-0 w-full h-full flex items-center justify-center bg-gray-800 bg-opacity-50 z-50">
<div className="bg-white max-w-4xl h-1/3 min-h-fit rounded-lg shadow-lg p-8 text-start flex flex-col justify-evenly">
<h1 className="text-red-500 text-3xl mb-4">Oops! An unknown error has occurred.</h1>
<p className="text-gray-700 mb-4 text-xl">
Please click the 'Reset Application' button
to restore the application's state. If the error persists, please
create an issue on our GitHub page. We apologize for any inconvenience
this may have caused.
</p>
<div className="flex justify-center">
<button
onClick={resetErrorBoundary}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mr-4"
>
Reset Application
</button>
<a
href="https://github.com/logspace-ai/langflow/issues/new"
target="_blank"
rel="noopener noreferrer"
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
>
Create Issue
</a>
</div>
</div>
</div>
);
}

View file

@ -6,7 +6,7 @@ import {
XMarkIcon,
} from "@heroicons/react/24/outline";
import { MouseEventHandler, useContext, useEffect, useRef, useState } from "react";
import { sendAll } from "../../controllers/NodesServices";
import { sendAll } from "../../controllers/API";
import { alertContext } from "../../contexts/alertContext";
import { classNames, nodeColors } from "../../utils";
import { TabsContext } from "../../contexts/tabsContext";
@ -97,7 +97,7 @@ export default function Chat({ flow, reactFlowInstance }: ChatType) {
setChatValue("");
addChatHistory(message, true);
sendAll({ ...reactFlowInstance.toObject(), message, chatHistory})
sendAll({ ...reactFlowInstance.toObject(), message, chatHistory,name:flow.name,description:flow.description})
.then((r) => {
addChatHistory(r.data.result, false, r.data.thought);
setLockChat(false);

View file

@ -0,0 +1,34 @@
import { ArrowTopRightOnSquareIcon } from "@heroicons/react/24/outline";
import { useContext, useEffect, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import CodeAreaModal from "../../modals/codeAreaModal";
import TextAreaModal from "../../modals/textAreaModal";
import { TextAreaComponentType } from "../../types/components";
export default function CodeAreaComponent({ value, onChange, disabled }:TextAreaComponentType) {
const [myValue, setMyValue] = useState(value);
const { openPopUp } = useContext(PopUpContext);
useEffect(() => {
if (disabled) {
setMyValue("");
onChange("");
}
}, [disabled, onChange]);
return (
<div className={disabled ? "pointer-events-none cursor-not-allowed" : ""}>
<div className="w-full flex items-center gap-3">
<span
className={
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
(disabled ? " bg-gray-200" : "")
}
>
{myValue !== "" ? myValue : 'Text empty'}
</span>
<button onClick={()=>{openPopUp(<CodeAreaModal value={myValue} setValue={(t:string) => {setMyValue(t); onChange(t);}}/>)}}>
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600" />
</button>
</div>
</div>
);
}

View file

@ -1,6 +1,7 @@
import { ArrowTopRightOnSquareIcon } from "@heroicons/react/24/outline";
import { useContext, useEffect, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import CodeAreaModal from "../../modals/codeAreaModal";
import TextAreaModal from "../../modals/textAreaModal";
import { TextAreaComponentType } from "../../types/components";
@ -9,8 +10,8 @@ export default function TextAreaComponent({ value, onChange, disabled }:TextArea
const { openPopUp } = useContext(PopUpContext);
useEffect(() => {
if (disabled) {
setMyValue([""]);
onChange([""]);
setMyValue("");
onChange("");
}
}, [disabled, onChange]);
return (

View file

@ -13,11 +13,13 @@ export default function ContextWrapper({ children }: { children: ReactNode }) {
<DarkProvider>
<LocationProvider>
<AlertProvider>
<TabsProvider>
<PopUpProvider>
<TypesProvider>
<TabsProvider>{children}</TabsProvider>
{children}
</TypesProvider>
</PopUpProvider>
</TabsProvider>
</AlertProvider>
</LocationProvider>
</DarkProvider>

View file

@ -12,10 +12,11 @@ const TabsContextInitialValue: TabsContextType = {
addFlow: (flowData?: any) => {},
updateFlow: (newFlow: FlowType) => {},
incrementNodeId: () => 0,
downloadFlow: () => {},
downloadFlow: (flow:FlowType) => {},
uploadFlow: () => {},
lockChat: false,
setLockChat:(prevState:boolean)=>{}
setLockChat:(prevState:boolean)=>{},
hardReset:()=>{}
};
export const TabsContext = createContext<TabsContextType>(
@ -54,14 +55,18 @@ export function TabsProvider({ children }: { children: ReactNode }) {
newNodeId.current = cookieObject.nodeId;
}
}, []);
function hardReset(){
newNodeId.current=0;
setTabIndex(0);setFlows([]);setId(0);
}
/**
* Downloads the current flow as a JSON file
*/
function downloadFlow() {
function downloadFlow(flow:FlowType) {
// create a data URI with the current flow data
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
JSON.stringify(flows[tabIndex])
JSON.stringify(flow)
)}`;
// create a link element and set its properties
@ -71,7 +76,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
// simulate a click on the link element to trigger the download
link.click();
setNoticeData({title:"Warning: Critical data, including API keys, in JSON file. Keep secure and do not share."})
setNoticeData({title:"Warning: Critical data,JSON file may including API keys."})
}
/**
@ -128,9 +133,11 @@ export function TabsProvider({ children }: { children: ReactNode }) {
function addFlow(flow?: FlowType) {
// Get data from the flow or set it to null if there's no flow provided.
const data = flow?.data ? flow.data : null;
const description = flow?.description?flow.description:""
// Create a new flow with a default name if no flow is provided.
let newFlow: FlowType = {
description,
name: "New Flow",
id: id.toString(),
data,
@ -158,6 +165,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
const newFlows = [...prevState];
const index = newFlows.findIndex((flow) => flow.id === newFlow.id);
if (index !== -1) {
newFlows[index].description = newFlow.description??""
newFlows[index].data = newFlow.data;
newFlows[index].name = newFlow.name;
newFlows[index].chat = newFlow.chat;
@ -169,6 +177,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
return (
<TabsContext.Provider
value={{
hardReset,
lockChat,
setLockChat,
tabIndex,

View file

@ -7,4 +7,9 @@ export async function getAll():Promise<AxiosResponse<APIObjectType>> {
export async function sendAll(data:sendAllProps) {
return await axios.post(`/predict`, data);
}
export async function checkCode(code:string){
return await axios.post('/validate',{code})
}

View file

@ -1,18 +1,19 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import ContextWrapper from './contexts';
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
import ContextWrapper from "./contexts";
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
document.getElementById("root") as HTMLElement
);
root.render(
<ContextWrapper>
<BrowserRouter>
<App />
</BrowserRouter>
</ContextWrapper>
<ContextWrapper>
<BrowserRouter>
<App />
</BrowserRouter>
</ContextWrapper>
);
reportWebVitals();

View file

@ -0,0 +1,149 @@
import { Dialog, Transition } from "@headlessui/react";
import { XMarkIcon, CommandLineIcon } from "@heroicons/react/24/outline";
import { Fragment, useContext, useRef, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-python";
import "ace-builds/src-noconflict/theme-github";
import "ace-builds/src-noconflict/theme-twilight";
import "ace-builds/src-noconflict/ext-language_tools";
import "ace-builds/webpack-resolver";
import { darkContext } from "../../contexts/darkContext";
import { checkCode } from "../../controllers/API";
import { alertContext } from "../../contexts/alertContext";
export default function CodeAreaModal({
value,
setValue,
}: {
setValue: (value: string) => void;
value: string;
}) {
const [open, setOpen] = useState(true);
const [code, setCode] = useState(value);
const { dark } = useContext(darkContext);
const { setErrorData, setSuccessData } = useContext(alertContext);
const { closePopUp } = useContext(PopUpContext);
const ref = useRef();
function setModalOpen(x: boolean) {
setOpen(x);
if (x === false) {
setTimeout(() => {
closePopUp();
}, 300);
}
}
return (
<Transition.Root show={open} appear={true} as={Fragment}>
<Dialog
as="div"
className="relative z-10"
onClose={setModalOpen}
initialFocus={ref}
>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
<button
type="button"
className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
onClick={() => {
setModalOpen(false);
}}
>
<span className="sr-only">Close</span>
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div className="h-full w-full flex flex-col justify-center items-center">
<div className="flex w-full pb-4 z-10 justify-center shadow-sm">
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
<CommandLineIcon
className="h-6 w-6 text-blue-600"
aria-hidden="true"
/>
</div>
<div className="mt-4 text-center sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium dark:text-white leading-10 text-gray-900"
>
Edit Code
</Dialog.Title>
</div>
</div>
<div className="h-full w-full bg-gray-200 overflow-auto dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
<div className="flex h-full w-full">
<div className="overflow-hidden px-4 py-5 sm:p-6 w-full h-full rounded-lg bg-white dark:bg-gray-800 shadow">
{/* need to insert code editor */}
<AceEditor
value={code}
mode="python"
highlightActiveLine={true}
showPrintMargin={false}
fontSize={14}
showGutter
enableLiveAutocompletion
theme={dark ? "twilight" : "github"}
name="CodeEditor"
onChange={(value) => {
setCode(value);
}}
className="h-full w-full rounded-lg"
/>
</div>
</div>
</div>
<div className="bg-gray-200 dark:bg-gray-900 w-full pb-3 flex flex-row-reverse px-4">
<button
type="button"
className="inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm"
onClick={() => {
setValue(code)
checkCode(code)
.then((_) =>{
setSuccessData({ title: "Code is ready to run" })
setModalOpen(false)
}
)
.catch((_) =>
setErrorData({
title:
"There is something wrong with this code, please review it",
})
);
}}
>
Check & Save
</button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
);
}

View file

@ -0,0 +1,174 @@
import { Dialog, Transition } from "@headlessui/react";
import {
XMarkIcon,
ArrowDownTrayIcon,
DocumentDuplicateIcon,
ComputerDesktopIcon,
} from "@heroicons/react/24/outline";
import { Fragment, useContext, useRef, useState } from "react";
import { alertContext } from "../../contexts/alertContext";
import { PopUpContext } from "../../contexts/popUpContext";
import { TabsContext } from "../../contexts/tabsContext";
import { removeApiKeys } from "../../utils";
export default function ExportModal() {
const [open, setOpen] = useState(true);
const { closePopUp } = useContext(PopUpContext);
const ref = useRef();
const {setErrorData}= useContext(alertContext)
const { flows, tabIndex, updateFlow, downloadFlow } = useContext(TabsContext);
function setModalOpen(x: boolean) {
setOpen(x);
if (x === false) {
setTimeout(() => {
closePopUp();
}, 300);
}
}
const [checked,setChecked] = useState(true)
return (
<Transition.Root show={open} appear={true} as={Fragment}>
<Dialog
as="div"
className="relative z-10"
onClose={setModalOpen}
initialFocus={ref}
>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
<button
type="button"
className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
onClick={() => {
setModalOpen(false);
}}
>
<span className="sr-only">Close</span>
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div className="h-full w-full flex flex-col justify-center items-center">
<div className="flex w-full pb-4 z-10 justify-center shadow-sm">
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
<ArrowDownTrayIcon
className="h-6 w-6 text-blue-600"
aria-hidden="true"
/>
</div>
<div className="mt-4 text-center sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium dark:text-white leading-10 text-gray-900"
>
Export as
</Dialog.Title>
</div>
</div>
<div className="pt-16 flex flex-col items-start justify-start h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-16">
<div className="w-full">
<label
htmlFor="name"
className="block mb-2 font-medium text-gray-700 dark:text-white"
>
Name
</label>
<input
onChange={(event) => {
if(event.target.value!=""){
let newFlow = flows[tabIndex];
newFlow.name = event.target.value;
updateFlow(newFlow);
}
else{
setErrorData({title:"Flow name can't be empty"})
}
}}
type="text"
name="name"
value={flows[tabIndex].name ?? null}
placeholder="File name"
id="name"
className="focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
/>
</div>
<div className="w-full">
<label
htmlFor="description"
className="block mb-2 font-medium text-gray-700 dark:text-white"
>
Description <span className="text-gray-400 text-sm"> (optional)</span>
</label>
<textarea
name="description"
id="description"
onChange={(event) => {
let newFlow = flows[tabIndex];
newFlow.description = event.target.value;
updateFlow(newFlow);
}}
value={flows[tabIndex].description ?? null}
placeholder="Flow description"
rows={3}
className=" focus:border focus:border-blue block w-full px-3 py-2 border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
></textarea>
</div>
<div>
<label htmlFor="checkbox" className="flex items-center">
<input
onChange={(event) => {
setChecked(event.target.checked)
}}
checked={checked}
id="checkbox"
type="checkbox"
className="h-4 w-4 text-blue-600 border-gray-300 rounded dark:bg-gray-800 dark:border-gray-600 dark:focus:border-blue-500 dark:focus:ring-blue-500"
/>
<span className="ml-2 font-medium text-gray-700 dark:text-white">
Save with my API keys
</span>
</label>
</div>
<div className="w-full flex justify-end">
<button
onClick={() => {
if(checked) downloadFlow(flows[tabIndex]);
else downloadFlow(removeApiKeys(flows[tabIndex]))
}}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Download Flow
</button>
</div>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
);
}

View file

@ -0,0 +1,47 @@
import React, { ReactNode } from "react";
import { DocumentDuplicateIcon } from "@heroicons/react/solid";
import { classNames } from "../../../utils";
export default function ButtonBox({
onClick,
title,
description,
icon,
bgColor,
textColor,
deactivate
}: {
onClick: () => void;
title: string;
description: string;
icon: ReactNode;
bgColor: string;
textColor: string;
deactivate?:boolean;
}) {
return (
<button disabled={deactivate} onClick={onClick}>
<div
className={classNames(
"col-span-1 flex flex-col divide-y divide-gray-200 rounded-lg text-center shadow border border-gray-300 hover:shadow-lg transform hover:scale-105",
bgColor
)}
>
<div className="flex flex-1 flex-col p-8">
<div className="mx-auto flex items-center justify-center h-20 w-20 bg-white/30 rounded-full">
<div className="mx-auto flex items-center justify-center h-16 w-16 bg-white rounded-full">
<div className={textColor}>
{icon}
</div>
</div>
</div>
<h3 className="mt-6 text-lg font-semibold text-white">{title}</h3>
<div className="mt-1 flex flex-grow flex-col justify-between">
<dt className="sr-only">{title}</dt>
<dd className="text-sm text-gray-100">{deactivate? "cooming soon":description}</dd>
</div>
</div>
</div>
</button>
);
}

View file

@ -0,0 +1,122 @@
import { Dialog, Transition } from "@headlessui/react";
import {
XMarkIcon,
ArrowDownTrayIcon,
DocumentDuplicateIcon,
ComputerDesktopIcon,
ArrowUpTrayIcon,
} from "@heroicons/react/24/outline";
import { Fragment, useContext, useRef, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import { TabsContext } from "../../contexts/tabsContext";
import ButtonBox from "./buttonBox";
export default function ImportModal() {
const [open, setOpen] = useState(true);
const { closePopUp } = useContext(PopUpContext);
const ref = useRef();
const {uploadFlow} = useContext(TabsContext)
function setModalOpen(x: boolean) {
setOpen(x);
if (x === false) {
setTimeout(() => {
closePopUp();
}, 300);
}
}
return (
<Transition.Root show={open} appear={true} as={Fragment}>
<Dialog
as="div"
className="relative z-10"
onClose={setModalOpen}
initialFocus={ref}
>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
<button
type="button"
className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
onClick={() => {
setModalOpen(false);
}}
>
<span className="sr-only">Close</span>
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div className="h-full w-full flex flex-col justify-center items-center">
<div className="flex w-full pb-4 z-10 justify-center shadow-sm">
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
<ArrowUpTrayIcon
className="h-6 w-6 text-blue-600"
aria-hidden="true"
/>
</div>
<div className="mt-4 text-center sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium dark:text-white leading-10 text-gray-900"
>
Import from
</Dialog.Title>
</div>
</div>
<div className="h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
<div className="flex h-full w-full justify-evenly items-center">
<ButtonBox
deactivate
bgColor="bg-slate-400"
description="Prebuilt Examples"
icon={
<DocumentDuplicateIcon className="h-10 w-10 flex-shrink-0" />
}
onClick={() => console.log("sdsds")}
textColor="text-slate-400"
title="Examples"
></ButtonBox>
<ButtonBox
bgColor="bg-blue-500"
description="Import from Local"
icon={
<ComputerDesktopIcon className="h-10 w-10 flex-shrink-0" />
}
onClick={() => {uploadFlow();setModalOpen(false)}}
textColor="text-blue-500"
title="Local file"
></ButtonBox>
</div>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
);
}

View file

@ -6,7 +6,7 @@ import {
nodeNames,
} from "../../../../utils";
import { useContext, useEffect, useState } from "react";
import { getAll } from "../../../../controllers/NodesServices";
import { getAll } from "../../../../controllers/API";
import { typesContext } from "../../../../contexts/typesContext";
import { APIClassType, APIKindType, APIObjectType } from "../../../../types/api";
@ -55,7 +55,7 @@ export default function ExtraSidebar() {
{Object.keys(data).map((d:keyof APIObjectType, i) => (
<DisclosureComponent
key={i}
button={{ title: nodeNames[d], Icon: nodeIcons[d] }}
button={{ title: nodeNames[d]??nodeNames.unknown, Icon: nodeIcons[d]??nodeIcons.unknown }}
>
<div className="p-2 flex flex-col gap-2">
{Object.keys(data[d]).map((t: string, k) => (
@ -63,7 +63,7 @@ export default function ExtraSidebar() {
<div
draggable
className={" cursor-grab border-l-8 rounded-l-md"}
style={{ borderLeftColor: nodeColors[d] }}
style={{ borderLeftColor: nodeColors[d]??nodeColors.unknown }}
onDragStart={(event) =>
onDragStart(event, {
type: t,

View file

@ -14,9 +14,12 @@ import {
import { PopUpContext } from "../../../../contexts/popUpContext";
import AlertDropdown from "../../../../alerts/alertDropDown";
import { alertContext } from "../../../../contexts/alertContext";
import ImportModal from "../../../../modals/importModal";
import ExportModal from "../../../../modals/exportModal";
export default function TabsManagerComponent() {
const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } = useContext(TabsContext);
const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } =
useContext(TabsContext);
const { openPopUp } = useContext(PopUpContext);
const AlertWidth = 256;
const { dark, setDark } = useContext(darkContext);
@ -50,10 +53,21 @@ export default function TabsManagerComponent() {
flow={null}
/>
<div className="ml-auto mr-2 flex gap-3">
<button onClick={() => uploadFlow()} className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-400 hover:text-gray-500">
<button
onClick={() =>
openPopUp(
<ImportModal
/>
)
}
className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-400 hover:text-gray-500"
>
Import <ArrowUpTrayIcon className="w-5 h-5" />
</button>
<button onClick={() => downloadFlow()} className="flex items-center gap-1 mr-2 text-sm text-gray-400 hover:text-gray-500">
<button
onClick={() =>openPopUp(<ExportModal/>)}
className="flex items-center gap-1 mr-2 text-sm text-gray-400 hover:text-gray-500"
>
Export <ArrowDownTrayIcon className="h-5 w-5" />
</button>
<button

View file

@ -17,10 +17,6 @@ import GenericNode from "../../CustomNodes/GenericNode";
import { alertContext } from "../../contexts/alertContext";
import { TabsContext } from "../../contexts/tabsContext";
import { typesContext } from "../../contexts/typesContext";
import {
ArrowDownTrayIcon,
ArrowUpTrayIcon,
} from "@heroicons/react/24/outline";
import ConnectionLineComponent from "./components/ConnectionLineComponent";
import { FlowType, NodeType } from "../../types/flow";
import { APIClassType } from "../../types/api";

View file

@ -9,7 +9,10 @@ export type TemplateVariableType = {type:string,required:boolean,placeholder?:st
export type sendAllProps={
nodes: Node[];
edges: Edge[];
name:string,
description:string;
viewport: Viewport;
message:string;
chatHistory:{message:string,isSend:boolean}[],
};

View file

@ -36,7 +36,7 @@ export type InputListComponentType = {
export type TextAreaComponentType = {
disabled: boolean;
onChange: (value: string[] | string) => void;
value: string[] | string;
value: string;
};
export type DisclosureComponentType = {

View file

@ -7,6 +7,7 @@ export type FlowType = {
id: string;
data: ReactFlowJsonObject;
chat: Array<ChatMessageType>;
description:string;
};
export type NodeType = {id:string,type:string,position:XYPosition,data:NodeDataType}
export type NodeDataType = {type:string,node?:APIClassType,id:string,value:any}

View file

@ -8,8 +8,9 @@ export type TabsContextType = {
addFlow: (flowData?: any) => void;
updateFlow: (newFlow: FlowType) => void;
incrementNodeId: () => number;
downloadFlow: () => void;
downloadFlow: (flow:FlowType) => void;
uploadFlow: () => void;
lockChat:boolean,
setLockChat:(prevState:boolean)=>void
lockChat:boolean;
setLockChat:(prevState:boolean)=>void;
hardReset:()=>void;
};

View file

@ -7,8 +7,12 @@ import {
WrenchScrewdriverIcon,
ComputerDesktopIcon,
Bars3CenterLeftIcon,
PaperClipIcon,
QuestionMarkCircleIcon,
} from "@heroicons/react/24/outline";
import { Connection, Edge, Node, ReactFlowInstance } from "reactflow";
import { FlowType } from "./types/flow";
var _ = require('lodash')
export function classNames(...classes:Array<string>) {
return classes.filter(Boolean).join(" ");
@ -69,7 +73,9 @@ export const nodeColors: {[char: string]: string} = {
memories: "#FF9135",
advanced: "#000000",
chat: "#454173",
thought:"#272541"
thought:"#272541",
docloaders:"#FF9135",
unknown:"#9CA3AF"
};
export const nodeNames:{[char: string]: string} = {
@ -81,7 +87,8 @@ export const nodeNames:{[char: string]: string} = {
memories: "Memories",
advanced: "Advanced",
chat: "Chat",
docloaders:"Document Loader",
unknown:"Unknown"
};
export const nodeIcons:{[char: string]: React.ForwardRefExoticComponent<React.SVGProps<SVGSVGElement>>} = {
@ -93,6 +100,8 @@ export const nodeIcons:{[char: string]: React.ForwardRefExoticComponent<React.SV
tools: WrenchScrewdriverIcon,
advanced: ComputerDesktopIcon,
chat: Bars3CenterLeftIcon,
docloaders:Bars3CenterLeftIcon,
unknown:QuestionMarkCircleIcon
};
export const bgColors = {
@ -341,3 +350,17 @@ export function isValidConnection(
}
return false;
}
export function removeApiKeys(flow:FlowType):FlowType{
let cleanFLow = _.cloneDeep(flow)
cleanFLow.data.nodes.forEach(node=>{
for(const key in node.data.node.template)
{
if(key.includes('api')){
console.log(node.data.node.template[key])
node.data.node.template[key].value = ''
}
}
})
return cleanFLow
}