// Block library with actual parameters const BLOCK_LIBRARY = { 'import_tensorflow': { id: 'import_tensorflow', name: 'Import TensorFlow', category: 'IMPORT', description: 'Import TensorFlow library', color: '#FF6F00', inputs: [], outputs: ['library'], parameters: [] }, 'import_sklearn': { id: 'import_sklearn', name: 'Import Scikit-learn', category: 'IMPORT', description: 'Import scikit-learn', color: '#F7931E', inputs: [], outputs: ['library'], parameters: [] }, 'load_csv': { id: 'load_csv', name: 'Load CSV', category: 'DATA', description: 'Load data from CSV file', color: '#00FFA3', inputs: [], outputs: ['dataset'], parameters: [ { name: 'filepath', type: 'string', default: 'data.csv', required: true }, { name: 'separator', type: 'string', default: ',' } ] }, 'train_test_split': { id: 'train_test_split', name: 'Train/Test Split', category: 'PREPROCESSING', description: 'Split dataset', color: '#00D9FF', inputs: ['dataset'], outputs: ['X_train', 'X_test', 'y_train', 'y_test'], parameters: [ { name: 'test_size', type: 'number', default: 0.3 }, { name: 'target_column', type: 'string', default: 'target', required: true } ] }, 'create_random_forest': { id: 'create_random_forest', name: 'Random Forest', category: 'MODEL', description: 'Create Random Forest', color: '#9D4EDD', inputs: [], outputs: ['model'], parameters: [ { name: 'n_estimators', type: 'number', default: 100 }, { name: 'max_depth', type: 'number', default: 10 } ] }, 'create_cnn': { id: 'create_cnn', name: 'CNN Model', category: 'MODEL', description: 'Create CNN model', color: '#9D4EDD', inputs: [], outputs: ['model'], parameters: [ { name: 'input_shape', type: 'string', default: '(224, 224, 3)' }, { name: 'num_classes', type: 'number', default: 10 } ] }, 'train_sklearn_model': { id: 'train_sklearn_model', name: 'Train Model', category: 'TRAINING', description: 'Train sklearn model', color: '#FF6B35', inputs: ['model', 'X_train', 'y_train'], outputs: ['trained_model'], parameters: [] }, 'make_predictions': { id: 'make_predictions', name: 'Predict', category: 'PREDICTION', description: 'Make predictions', color: '#00FF88', inputs: ['model', 'X_test'], outputs: ['predictions'], parameters: [] } }; const BLOCK_CATEGORIES = { 'IMPORT': ['import_tensorflow', 'import_sklearn'], 'DATA': ['load_csv'], 'PREPROCESSING': ['train_test_split'], 'MODEL': ['create_random_forest', 'create_cnn'], 'TRAINING': ['train_sklearn_model'], 'PREDICTION': ['make_predictions'] }; function VisualMLBuilder() { const [nodes, setNodes] = useState([]); const [connections, setConnections] = useState([]); const [selectedNode, setSelectedNode] = useState(null); const [showCodeModal, setShowCodeModal] = useState(false); const [generatedCode, setGeneratedCode] = useState(''); const [draggedNode, setDraggedNode] = useState(null); const [connectingFrom, setConnectingFrom] = useState(null); const canvasRef = useRef(null); const svgRef = useRef(null); // Drag and Drop const handleDragStart = (e, blockId) => { e.dataTransfer.effectAllowed = 'copy'; e.dataTransfer.setData('blockId', blockId); }; const handleDragOver = (e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'copy'; }; const handleDrop = (e) => { e.preventDefault(); const blockId = e.dataTransfer.getData('blockId'); const blockDef = BLOCK_LIBRARY[blockId]; if (!blockDef) return; const rect = canvasRef.current.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const newNode = { id: `node_${Date.now()}`, blockType: blockId, name: blockDef.name, color: blockDef.color, x: x - 110, y: y - 50, inputs: blockDef.inputs, outputs: blockDef.outputs, parameters: {} }; // Initialize parameters with defaults blockDef.parameters.forEach(param => { newNode.parameters[param.name] = param.default; }); setNodes([...nodes, newNode]); }; // Node dragging const handleNodeMouseDown = (e, node) => { if (e.target.closest('.port-dot')) return; // Don't drag when clicking ports e.stopPropagation(); const startX = e.clientX - node.x; const startY = e.clientY - node.y; const handleMouseMove = (e) => { const rect = canvasRef.current.getBoundingClientRect(); const newX = e.clientX - rect.left - startX; const newY = e.clientY - rect.top - startY; setNodes(prev => prev.map(n => n.id === node.id ? { ...n, x: newX, y: newY } : n )); }; const handleMouseUp = () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); }; // Connection handling const handlePortClick = (nodeId, portName, isOutput) => { if (isOutput) { setConnectingFrom({ nodeId, portName }); } else if (connectingFrom) { // Create connection const newConnection = { id: `conn_${Date.now()}`, sourceNode: connectingFrom.nodeId, sourcePort: connectingFrom.portName, targetNode: nodeId, targetPort: portName }; setConnections([...connections, newConnection]); setConnectingFrom(null); } }; // Update parameter const updateParameter = (paramName, value) => { if (!selectedNode) return; setNodes(prev => prev.map(node => node.id === selectedNode.id ? { ...node, parameters: { ...node.parameters, [paramName]: value } } : node )); setSelectedNode(prev => ({ ...prev, parameters: { ...prev.parameters, [paramName]: value } })); }; // Delete node const deleteNode = (nodeId) => { setNodes(prev => prev.filter(n => n.id !== nodeId)); setConnections(prev => prev.filter(c => c.sourceNode !== nodeId && c.targetNode !== nodeId )); if (selectedNode?.id === nodeId) { setSelectedNode(null); } }; // Generate code from graph const generateCode = () => { if (nodes.length === 0) { alert('Add some blocks first!'); return; } // Build graph structure const graph = { blocks: nodes.map(node => ({ id: node.id, block_type: node.blockType, parameters: node.parameters })), connections: connections.map(conn => ({ id: conn.id, source_block: conn.sourceNode, source_port: conn.sourcePort, target_block: conn.targetNode, target_port: conn.targetPort })) }; // Simple code generation (mimics backend logic) let code = '"""\nAuto-generated ML Pipeline\nCreated by Visual ML Builder\n"""\n\n'; // Collect imports const imports = new Set(); nodes.forEach(node => { const blockDef = BLOCK_LIBRARY[node.blockType]; if (blockDef.category === 'IMPORT') { if (blockDef.id === 'import_tensorflow') { imports.add('import tensorflow as tf'); } else if (blockDef.id === 'import_sklearn') { imports.add('import sklearn'); imports.add('from sklearn.model_selection import train_test_split'); } } else if (blockDef.id === 'load_csv') { imports.add('import pandas as pd'); } else if (blockDef.id === 'create_random_forest') { imports.add('from sklearn.ensemble import RandomForestClassifier'); } }); code += Array.from(imports).join('\n') + '\n\n'; code += '# Main Pipeline\n\n'; // Generate code for each node (simplified) nodes.forEach((node, idx) => { const blockDef = BLOCK_LIBRARY[node.blockType]; const varName = `step_${idx + 1}`; code += `# ${node.name}\n`; switch(node.blockType) { case 'load_csv': code += `${varName} = pd.read_csv('${node.parameters.filepath}')\n`; break; case 'train_test_split': code += `X = step_${idx}.drop('${node.parameters.target_column}', axis=1)\n`; code += `y = step_${idx}['${node.parameters.target_column}']\n`; code += `X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=${node.parameters.test_size})\n`; break; case 'create_random_forest': code += `${varName} = RandomForestClassifier(n_estimators=${node.parameters.n_estimators}, max_depth=${node.parameters.max_depth})\n`; break; case 'create_cnn': code += `${varName} = tf.keras.Sequential([\n`; code += ` tf.keras.layers.Input(shape=${node.parameters.input_shape}),\n`; code += ` tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),\n`; code += ` tf.keras.layers.Dense(${node.parameters.num_classes}, activation='softmax')\n`; code += `])\n`; break; case 'train_sklearn_model': code += `# Training\n`; code += `step_${idx}.fit(X_train, y_train)\n`; break; case 'make_predictions': code += `${varName} = step_${idx}.predict(X_test)\n`; break; } code += '\n'; }); code += 'print("Pipeline executed successfully!")\n'; setGeneratedCode(code); setShowCodeModal(true); }; // Draw connections useEffect(() => { if (!svgRef.current) return; const svg = svgRef.current; svg.innerHTML = ''; connections.forEach(conn => { const sourceNode = nodes.find(n => n.id === conn.sourceNode); const targetNode = nodes.find(n => n.id === conn.targetNode); if (!sourceNode || !targetNode) return; // Calculate connection positions const x1 = sourceNode.x + 220; const y1 = sourceNode.y + 60; const x2 = targetNode.x; const y2 = targetNode.y + 60; const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); const midX = (x1 + x2) / 2; path.setAttribute('d', `M ${x1} ${y1} C ${midX} ${y1}, ${midX} ${y2}, ${x2} ${y2}`); path.setAttribute('stroke', sourceNode.color); path.setAttribute('stroke-width', '2'); path.setAttribute('fill', 'none'); path.setAttribute('opacity', '0.6'); svg.appendChild(path); }); }, [nodes, connections]); return ( <>
⚑ Visual ML Builder
{Object.entries(BLOCK_CATEGORIES).map(([category, blockIds]) => (

{category}

{blockIds.map(blockId => { const block = BLOCK_LIBRARY[blockId]; return (
handleDragStart(e, blockId)} style={{ '--block-color': block.color }} >
{block.name}
{block.description}
); })}
))}
{nodes.map(node => (
handleNodeMouseDown(e, node)} onClick={() => setSelectedNode(node)} >
{node.name.charAt(0)}
{node.name}
{node.inputs.map(input => (
{ e.stopPropagation(); handlePortClick(node.id, input, false); }} style={{ cursor: 'pointer' }} /> {input}
))} {node.outputs.map(output => (
{output}
{ e.stopPropagation(); handlePortClick(node.id, output, true); }} style={{ cursor: 'pointer' }} />
))}
))} {nodes.length === 0 && (
Drag blocks from the sidebar to start building your pipeline
)}

{selectedNode ? 'Block Properties' : 'No Block Selected'}

{selectedNode && ( <>
{BLOCK_LIBRARY[selectedNode.blockType]?.parameters.map(param => (
updateParameter(param.name, param.type === 'number' ? parseFloat(e.target.value) : e.target.value)} />
))} )}
Ready
{nodes.length} blocks | {connections.length} connections
{showCodeModal && (
setShowCodeModal(false)}>
e.stopPropagation()}>
Generated Python Code
{generatedCode}
)} ); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render();