|
|
import React, { useCallback, useEffect, useState } from 'react'; |
|
|
import ReactFlow, { Controls, useNodesState, useEdgesState, addEdge, Node, Edge } from 'reactflow'; |
|
|
import { FiFile } from 'react-icons/fi'; |
|
|
|
|
|
import 'reactflow/dist/base.css'; |
|
|
import './index.css'; |
|
|
import TurboNode, { TurboNodeData } from './TurboNode'; |
|
|
import TurboEdge from './TurboEdge'; |
|
|
import FunctionIcon from './FunctionIcon'; |
|
|
import Sidebar from './Sidebar'; |
|
|
|
|
|
const initialNodes: Node<TurboNodeData>[] = [ |
|
|
{ |
|
|
id: '1', |
|
|
position: { x: 0, y: 0 }, |
|
|
data: { |
|
|
icon: <FunctionIcon />, |
|
|
title: 'LLM Provider', |
|
|
subline: 'Select the LLM provider', |
|
|
inputFields: [], |
|
|
options: [ |
|
|
{ id: 'provider-openai', label: 'OpenAI', checked: true }, |
|
|
{ id: 'provider-azure', label: 'Azure', checked: false }, |
|
|
{ id: 'provider-cohere', label: 'Cohere', checked: false }, |
|
|
{ id: 'provider-huggingface', label: 'Hugging Face', checked: false }, |
|
|
{ id: 'provider-anthropic', label: 'Anthropic', checked: false }, |
|
|
], |
|
|
}, |
|
|
type: 'turbo', |
|
|
}, |
|
|
{ |
|
|
id: '2', |
|
|
position: { x: 250, y: 0 }, |
|
|
data: { |
|
|
icon: <FunctionIcon />, |
|
|
title: 'Model Selection', |
|
|
subline: 'Choose the LLM model', |
|
|
inputFields: [], |
|
|
options: [ |
|
|
{ id: 'model-gpt-3.5-turbo', label: 'GPT-3.5-turbo', checked: true }, |
|
|
{ id: 'model-gpt-4', label: 'GPT-4', checked: false }, |
|
|
{ id: 'model-claude', label: 'Claude', checked: false }, |
|
|
{ id: 'model-flan-t5', label: 'Flan-T5', checked: false }, |
|
|
], |
|
|
}, |
|
|
type: 'turbo', |
|
|
}, |
|
|
{ |
|
|
id: '3', |
|
|
position: { x: 500, y: 0 }, |
|
|
data: { |
|
|
icon: <FunctionIcon />, |
|
|
title: 'Prompt Engineering', |
|
|
subline: 'Configure prompt settings', |
|
|
inputFields: [ |
|
|
{ id: 'prompt-template', label: 'Prompt Template', value: '' }, |
|
|
{ id: 'prompt-examples', label: 'Prompt Examples', value: '' }, |
|
|
], |
|
|
options: [ |
|
|
{ id: 'prompt-fewshot', label: 'Few-shot Learning', checked: false }, |
|
|
{ id: 'prompt-cot', label: 'Chain-of-Thought', checked: false }, |
|
|
], |
|
|
}, |
|
|
type: 'turbo', |
|
|
}, |
|
|
{ |
|
|
id: '4', |
|
|
position: { x: 750, y: 0 }, |
|
|
data: { |
|
|
icon: <FunctionIcon />, |
|
|
title: 'API Settings', |
|
|
subline: 'Set API parameters', |
|
|
inputFields: [ |
|
|
{ id: 'api-key', label: 'API Key', value: '' }, |
|
|
{ id: 'api-base', label: 'API Base URL', value: '' }, |
|
|
], |
|
|
options: [ |
|
|
{ id: 'api-streaming', label: 'Enable Streaming', checked: false }, |
|
|
{ id: 'api-retry', label: 'Enable Auto-Retry', checked: true }, |
|
|
], |
|
|
}, |
|
|
type: 'turbo', |
|
|
}, |
|
|
{ |
|
|
id: '5', |
|
|
position: { x: 1000, y: 0 }, |
|
|
data: { |
|
|
icon: <FiFile />, |
|
|
title: 'Output', |
|
|
subline: 'Generated output from LLM', |
|
|
}, |
|
|
type: 'turbo', |
|
|
}, |
|
|
]; |
|
|
|
|
|
const initialEdges: Edge[] = [ |
|
|
{ |
|
|
id: 'e1-2', |
|
|
source: '1', |
|
|
target: '2', |
|
|
}, |
|
|
{ |
|
|
id: 'e2-3', |
|
|
source: '2', |
|
|
target: '3', |
|
|
}, |
|
|
{ |
|
|
id: 'e3-4', |
|
|
source: '3', |
|
|
target: '4', |
|
|
}, |
|
|
{ |
|
|
id: 'e4-5', |
|
|
source: '4', |
|
|
target: '5', |
|
|
}, |
|
|
]; |
|
|
|
|
|
const nodeTypes = { |
|
|
turbo: TurboNode, |
|
|
}; |
|
|
|
|
|
const edgeTypes = { |
|
|
turbo: TurboEdge, |
|
|
}; |
|
|
|
|
|
const defaultEdgeOptions = { |
|
|
type: 'turbo', |
|
|
markerEnd: 'edge-circle', |
|
|
}; |
|
|
|
|
|
const App = () => { |
|
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); |
|
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); |
|
|
const [recursiveSteps, setRecursiveSteps] = useState(1); |
|
|
const [inputData, setInputData] = useState(''); |
|
|
|
|
|
const onConnect = useCallback((params) => setEdges((els) => addEdge(params, els)), []); |
|
|
|
|
|
const addRecursiveStep = () => { |
|
|
setRecursiveSteps((prevSteps) => prevSteps + 1); |
|
|
}; |
|
|
|
|
|
const removeRecursiveStep = () => { |
|
|
if (recursiveSteps > 1) { |
|
|
setRecursiveSteps((prevSteps) => prevSteps - 1); |
|
|
} |
|
|
}; |
|
|
|
|
|
const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => { |
|
|
setInputData(event.target.value); |
|
|
}; |
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, [recursiveSteps, inputData]); |
|
|
|
|
|
return ( |
|
|
<div className="flow-container"> |
|
|
<ReactFlow |
|
|
nodes={nodes} |
|
|
edges={edges} |
|
|
onNodesChange={onNodesChange} |
|
|
onEdgesChange={onEdgesChange} |
|
|
onConnect={onConnect} |
|
|
fitView |
|
|
nodeTypes={nodeTypes} |
|
|
edgeTypes={edgeTypes} |
|
|
defaultEdgeOptions={defaultEdgeOptions} |
|
|
> |
|
|
<Controls showInteractive={false} /> |
|
|
<svg> |
|
|
<defs> |
|
|
<linearGradient id="edge-gradient"> |
|
|
<stop offset="0%" stopColor="#ae53ba" /> |
|
|
<stop offset="100%" stopColor="#2a8af6" /> |
|
|
</linearGradient> |
|
|
|
|
|
<marker |
|
|
id="edge-circle" |
|
|
viewBox="-5 -5 10 10" |
|
|
refX="0" |
|
|
refY="0" |
|
|
markerUnits="strokeWidth" |
|
|
markerWidth="10" |
|
|
markerHeight="10" |
|
|
orient="auto" |
|
|
> |
|
|
<circle stroke="#2a8af6" strokeOpacity="0.75" r="2" cx="0" cy="0" /> |
|
|
</marker> |
|
|
</defs> |
|
|
</svg> |
|
|
</ReactFlow> |
|
|
<Sidebar |
|
|
recursiveSteps={recursiveSteps} |
|
|
addRecursiveStep={addRecursiveStep} |
|
|
removeRecursiveStep={removeRecursiveStep} |
|
|
inputData={inputData} |
|
|
handleInputChange={handleInputChange} |
|
|
/> |
|
|
</div> |
|
|
); |
|
|
}; |
|
|
|
|
|
export default App; |