String and chat nodes added, handles design changed
This commit is contained in:
parent
b7718153bb
commit
3f7fb8a1b4
9 changed files with 180 additions and 31 deletions
21
space_flow/src/CustomNodes/ChatInputNode/index.tsx
Normal file
21
space_flow/src/CustomNodes/ChatInputNode/index.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { ChatBubbleBottomCenterTextIcon } from "@heroicons/react/24/outline";
|
||||||
|
import Input from "../../components/inputComponent";
|
||||||
|
import { snakeToNormalCase } from "../../utils";
|
||||||
|
import { Handle, Position } from "reactflow";
|
||||||
|
|
||||||
|
export default function ChatInputNode({ data }) {
|
||||||
|
return (
|
||||||
|
<div className="prompt-node relative rounded-lg solid border flex justify-center align-center py-3 px-6 bg-blue-600">
|
||||||
|
<Handle
|
||||||
|
type="target"
|
||||||
|
position={Position.Right}
|
||||||
|
id="b"
|
||||||
|
className="-mr-1 bg-transparent border-solid border-l-8 border-l-blue-600 border-y-transparent border-y-8 border-r-0 rounded-none"
|
||||||
|
></Handle>
|
||||||
|
<div className="flex gap-3 text-lg font-medium text-white items-center">
|
||||||
|
<ChatBubbleBottomCenterTextIcon className="h-8 w-8 mt-1" />
|
||||||
|
Input
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
space_flow/src/CustomNodes/ChatOutputNode/index.tsx
Normal file
23
space_flow/src/CustomNodes/ChatOutputNode/index.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ChatBubbleBottomCenterTextIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { Handle, Position } from "reactflow";
|
||||||
|
import Input from "../../components/inputComponent";
|
||||||
|
import { snakeToNormalCase } from "../../utils";
|
||||||
|
|
||||||
|
export default function ChatOutputNode({ data }) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="prompt-node relative rounded-lg solid border flex justify-center align-center py-3 px-6 bg-blue-600">
|
||||||
|
<Handle
|
||||||
|
type="source"
|
||||||
|
position={Position.Left}
|
||||||
|
id="b"
|
||||||
|
className="ml-1 bg-transparent border-solid border-l-8 border-l-white border-y-transparent border-y-8 border-r-0 rounded-none"
|
||||||
|
></Handle>
|
||||||
|
<div className="flex gap-3 text-lg font-medium text-white items-center">
|
||||||
|
Output
|
||||||
|
<ChatBubbleBottomCenterTextIcon className="h-8 w-8 mt-1" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,9 @@ export default function GenericNode({ data }) {
|
||||||
type="source"
|
type="source"
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
id="b"
|
id="b"
|
||||||
className="bg-gray-400 w-4 h-4 rounded-full"
|
isConnectable={false}
|
||||||
|
className="ml-1 bg-transparent border-solid border-l-8 border-y-transparent border-y-8 border-r-0 rounded-none"
|
||||||
|
style={{borderLeftColor: nodeColors[data.type]}}
|
||||||
></Handle>
|
></Handle>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<div className="w-full flex items-center justify-between p-4 bg-gray-50 border-b ">
|
<div className="w-full flex items-center justify-between p-4 bg-gray-50 border-b ">
|
||||||
|
|
@ -29,7 +31,6 @@ export default function GenericNode({ data }) {
|
||||||
/>
|
/>
|
||||||
{data.name}
|
{data.name}
|
||||||
</div>
|
</div>
|
||||||
<ArrowUpRightIcon className="w-4 h-4" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full p-5 h-full">
|
<div className="w-full p-5 h-full">
|
||||||
|
|
@ -46,7 +47,7 @@ export default function GenericNode({ data }) {
|
||||||
onSelect={() => {}}
|
onSelect={() => {}}
|
||||||
/>
|
/>
|
||||||
) : data.node.template[t].type === "str" ? (
|
) : data.node.template[t].type === "str" ? (
|
||||||
<Input title={snakeToNormalCase(t)} value={data.node.template[t].value} placeholder={data.node.template[t].placeholder??"aasas"} onChange={() => {}} />
|
<></>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
|
|
@ -59,16 +60,13 @@ export default function GenericNode({ data }) {
|
||||||
<button onClick={data.onDelete}>
|
<button onClick={data.onDelete}>
|
||||||
<TrashIcon className="w-6 h-6 hover:text-red-500"></TrashIcon>
|
<TrashIcon className="w-6 h-6 hover:text-red-500"></TrashIcon>
|
||||||
</button>
|
</button>
|
||||||
<button onClick={data.onRun}>
|
|
||||||
<PlayIcon className="w-6 h-6 hover:text-green-500"></PlayIcon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<Handle
|
<Handle
|
||||||
type="target"
|
type="target"
|
||||||
position={Position.Right}
|
position={Position.Right}
|
||||||
id="b"
|
id="b"
|
||||||
className="bg-gray-400 w-4 h-4 rounded-full"
|
className="-mr-1 bg-transparent border-solid border-l-8 border-y-transparent border-y-8 border-r-0 rounded-none"
|
||||||
style={{ background: nodeColors[data.type] }}
|
style={{borderLeftColor: nodeColors[data.type]}}
|
||||||
></Handle>
|
></Handle>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
41
space_flow/src/CustomNodes/InputNode/index.tsx
Normal file
41
space_flow/src/CustomNodes/InputNode/index.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { Bars3CenterLeftIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||||
|
import Input from "../../components/inputComponent";
|
||||||
|
import { nodeColors, nodeIcons, snakeToNormalCase } from "../../utils";
|
||||||
|
import { Handle, Position } from "reactflow";
|
||||||
|
|
||||||
|
export default function InputNode({ data }) {
|
||||||
|
return (
|
||||||
|
<div className="prompt-node relative bg-white w-96 rounded-lg solid border flex flex-col justify-center">
|
||||||
|
<div className="w-full flex items-center justify-between p-4 bg-gray-50 border-b ">
|
||||||
|
<div className="flex items-center gap-4 text-lg">
|
||||||
|
<Bars3CenterLeftIcon
|
||||||
|
className="w-10 h-10 p-1 text-white rounded"
|
||||||
|
style={{ background: nodeColors[data.type] }}
|
||||||
|
/>
|
||||||
|
String
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full p-5 h-full">
|
||||||
|
<Input
|
||||||
|
onChange={(e) => {
|
||||||
|
data.text = e;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex w-full justify-between items-center bg-gray-50 gap-2 border-t text-gray-600 p-4 text-sm">
|
||||||
|
<button onClick={() => {data.onDelete(data)}}>
|
||||||
|
<TrashIcon className="w-6 h-6 hover:text-red-500"></TrashIcon>
|
||||||
|
</button>
|
||||||
|
<button onClick={data.onRun}></button>
|
||||||
|
</div>
|
||||||
|
<Handle
|
||||||
|
type="target"
|
||||||
|
position={Position.Right}
|
||||||
|
id="b"
|
||||||
|
className="-mr-1 bg-transparent border-solid border-l-8 border-y-transparent border-y-8 border-r-0 rounded-none"
|
||||||
|
style={{borderLeftColor: nodeColors[data.type]}}
|
||||||
|
></Handle>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ import {
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function Chat() {
|
export default function Chat({nodes, edges}) {
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -53,7 +53,7 @@ export default function Chat() {
|
||||||
placeholder="Send a message..."
|
placeholder="Send a message..."
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-y-0 right-0 flex items-center pr-3">
|
<div className="absolute inset-y-0 right-0 flex items-center pr-3">
|
||||||
<button>
|
<button onClick={() => {console.log(nodes, edges)}}>
|
||||||
<PaperAirplaneIcon
|
<PaperAirplaneIcon
|
||||||
className="h-5 w-5 text-gray-400 hover:text-gray-600"
|
className="h-5 w-5 text-gray-400 hover:text-gray-600"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,14 @@
|
||||||
export default function Input({title, placeholder, onChange, value}){
|
export default function Input({onChange}){
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700">
|
|
||||||
{title}
|
|
||||||
</label>
|
|
||||||
<div className="mt-1">
|
|
||||||
<input
|
<input
|
||||||
value={(value as string)?.length>0?value:""}
|
|
||||||
type="text"
|
type="text"
|
||||||
className="block w-full form-input rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
className="block w-full form-input rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||||
placeholder={placeholder}
|
placeholder="Type a text"
|
||||||
onChange={onChange}
|
onChange={(e) => {
|
||||||
|
onChange(e.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Bars2Icon } from "@heroicons/react/24/outline";
|
import { Bars2Icon, ComputerDesktopIcon } from "@heroicons/react/24/outline";
|
||||||
import DisclosureComponent from "../DisclosureComponent";
|
import DisclosureComponent from "../DisclosureComponent";
|
||||||
import { nodeColors, nodeIcons, nodeNames, toFirstUpperCase } from "../../../../utils";
|
import { nodeColors, nodeIcons, nodeNames, toFirstUpperCase } from "../../../../utils";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
@ -58,6 +58,67 @@ export default function ExtraSidebar() {
|
||||||
</div>
|
</div>
|
||||||
</DisclosureComponent>
|
</DisclosureComponent>
|
||||||
))}
|
))}
|
||||||
|
<DisclosureComponent
|
||||||
|
button={{ title: nodeNames['elements'], Icon: nodeIcons['elements'] }}
|
||||||
|
>
|
||||||
|
<div className="p-2 flex flex-col gap-2">
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
draggable
|
||||||
|
className={" cursor-grab border-l-8 rounded-l-md"}
|
||||||
|
style={{ borderLeftColor: nodeColors['elements'] }}
|
||||||
|
onDragStart={(event) =>
|
||||||
|
onDragStart(event, {
|
||||||
|
type: 'elements',
|
||||||
|
name: 'str',
|
||||||
|
types: types
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex w-full justify-between text-sm px-4 py-3 items-center border-dashed border-gray-400 border-l-0 rounded-md rounded-l-none border-2">
|
||||||
|
<span className="text-black w-36 truncate">String</span>
|
||||||
|
<Bars2Icon className="w-6 h-6 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
draggable
|
||||||
|
className={" cursor-grab border-l-8 rounded-l-md"}
|
||||||
|
style={{ borderLeftColor: nodeColors['elements'] }}
|
||||||
|
onDragStart={(event) =>
|
||||||
|
onDragStart(event, {
|
||||||
|
type: 'elements',
|
||||||
|
name: 'chatInput',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex w-full justify-between text-sm px-4 py-3 items-center border-dashed border-gray-400 border-l-0 rounded-md rounded-l-none border-2">
|
||||||
|
<span className="text-black w-36 truncate">Chat Input</span>
|
||||||
|
<Bars2Icon className="w-6 h-6 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
draggable
|
||||||
|
className={" cursor-grab border-l-8 rounded-l-md"}
|
||||||
|
style={{ borderLeftColor: nodeColors['elements'] }}
|
||||||
|
onDragStart={(event) =>
|
||||||
|
onDragStart(event, {
|
||||||
|
type: 'elements',
|
||||||
|
name: 'chatOutput',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex w-full justify-between text-sm px-4 py-3 items-center border-dashed border-gray-400 border-l-0 rounded-md rounded-l-none border-2">
|
||||||
|
<span className="text-black w-36 truncate">Chat Output</span>
|
||||||
|
<Bars2Icon className="w-6 h-6 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DisclosureComponent>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
Controls,
|
Controls,
|
||||||
|
Edge,
|
||||||
addEdge,
|
addEdge,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
|
|
@ -12,8 +13,14 @@ import Chat from "../../components/chatComponent";
|
||||||
import GenericNode from "../../CustomNodes/GenericNode";
|
import GenericNode from "../../CustomNodes/GenericNode";
|
||||||
import connection from "./components/connection";
|
import connection from "./components/connection";
|
||||||
import { getConnectedNodes } from "../../utils";
|
import { getConnectedNodes } from "../../utils";
|
||||||
|
import ChatInputNode from "../../CustomNodes/ChatInputNode";
|
||||||
|
import ChatOutputNode from "../../CustomNodes/ChatOutputNode";
|
||||||
|
import InputNode from "../../CustomNodes/InputNode";
|
||||||
const nodeTypes = {
|
const nodeTypes = {
|
||||||
genericNode:GenericNode,
|
genericNode:GenericNode,
|
||||||
|
inputNode: InputNode,
|
||||||
|
chatInputNode:ChatInputNode,
|
||||||
|
chatOutputNode:ChatOutputNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function FlowPage() {
|
export default function FlowPage() {
|
||||||
|
|
@ -60,11 +67,12 @@ export default function FlowPage() {
|
||||||
x: event.clientX - reactflowBounds.left,
|
x: event.clientX - reactflowBounds.left,
|
||||||
y: event.clientY - reactflowBounds.top,
|
y: event.clientY - reactflowBounds.top,
|
||||||
});
|
});
|
||||||
|
let newId = getId();
|
||||||
const newNode = {
|
const newNode = {
|
||||||
id: getId(),
|
id: newId,
|
||||||
type: 'genericNode',
|
type: data.name === 'str' ? 'inputNode' : (data.name === 'chatInput' ? 'chatInputNode' : (data.name === 'chatOutput' ? 'chatOutputNode' : 'genericNode')),
|
||||||
position,
|
position,
|
||||||
data: { ...data, onDelete: () => console.log("asdsdsadad"), onRun: () => {} },
|
data: { ...data, onDelete: () => {setNodes(reactFlowInstance.getNodes().filter((n)=>n.id !== newId))} },
|
||||||
};
|
};
|
||||||
setNodes((nds) => nds.concat(newNode));
|
setNodes((nds) => nds.concat(newNode));
|
||||||
},
|
},
|
||||||
|
|
@ -89,7 +97,7 @@ export default function FlowPage() {
|
||||||
<Background />
|
<Background />
|
||||||
<Controls></Controls>
|
<Controls></Controls>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
<Chat />
|
<Chat nodes={nodes} edges={edges}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { RocketLaunchIcon, LinkIcon, CpuChipIcon, LightBulbIcon, CommandLineIcon, WrenchScrewdriverIcon } from "@heroicons/react/24/outline";
|
import { RocketLaunchIcon, LinkIcon, CpuChipIcon, LightBulbIcon, CommandLineIcon, WrenchScrewdriverIcon, ComputerDesktopIcon } from "@heroicons/react/24/outline";
|
||||||
import { Edge, Node } from "reactflow";
|
import { Edge, Node } from "reactflow";
|
||||||
|
|
||||||
export function classNames(...classes) {
|
export function classNames(...classes) {
|
||||||
|
|
@ -94,6 +94,7 @@ export function classNames(...classes) {
|
||||||
agents: "#903BBE",
|
agents: "#903BBE",
|
||||||
tools: "#FF3434",
|
tools: "#FF3434",
|
||||||
memories: "#FF9135",
|
memories: "#FF9135",
|
||||||
|
elements: "#6344BE"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const nodeNames = {
|
export const nodeNames = {
|
||||||
|
|
@ -103,6 +104,7 @@ export function classNames(...classes) {
|
||||||
agents: "Agents",
|
agents: "Agents",
|
||||||
tools: "Tools",
|
tools: "Tools",
|
||||||
memories: "Memories",
|
memories: "Memories",
|
||||||
|
elements: "Elements",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -113,6 +115,7 @@ export function classNames(...classes) {
|
||||||
llms: LightBulbIcon,
|
llms: LightBulbIcon,
|
||||||
prompts: CommandLineIcon,
|
prompts: CommandLineIcon,
|
||||||
tools: WrenchScrewdriverIcon,
|
tools: WrenchScrewdriverIcon,
|
||||||
|
elements: ComputerDesktopIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
export const bgColors = {
|
export const bgColors = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue