wuhp commited on
Commit
d137c87
·
verified ·
1 Parent(s): 6274817

Update App.tsx

Browse files
Files changed (1) hide show
  1. App.tsx +60 -16
App.tsx CHANGED
@@ -1,4 +1,5 @@
1
 
 
2
  import React, { useCallback, useRef, useState, useMemo, useEffect } from 'react';
3
  import ReactFlow, {
4
  ReactFlowProvider,
@@ -25,7 +26,7 @@ import ApiKeyModal from './components/ApiKeyModal';
25
  import FixerModal from './components/FixerModal';
26
  import { INITIAL_NODES, INITIAL_EDGES, LAYER_DEFINITIONS, TEMPLATES } from './constants';
27
  import { generateRefinedPrompt, validateArchitecture, getArchitectureSuggestions, getUserApiKey, implementArchitectureSuggestions } from './services/geminiService';
28
- import { NodeData, LayerType } from './types';
29
 
30
  let id = 1000;
31
  const getId = () => `${id++}`;
@@ -61,10 +62,23 @@ const AppContent = () => {
61
  const [isApiKeyModalOpen, setIsApiKeyModalOpen] = useState(false);
62
  const [isConnected, setIsConnected] = useState(false);
63
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  // Load connection status on mount
65
  useEffect(() => {
66
  setIsConnected(!!getUserApiKey());
67
- }, []);
 
68
 
69
  // Define custom node types
70
  const nodeTypes = useMemo(() => ({ custom: CustomNode }), []);
@@ -94,12 +108,13 @@ const AppContent = () => {
94
  y: event.clientY,
95
  });
96
 
 
97
  const newNode: Node<NodeData> = {
98
  id: getId(),
99
  type: 'custom',
100
  position,
101
  data: {
102
- label: LAYER_DEFINITIONS[type].label,
103
  type: type,
104
  params: LAYER_DEFINITIONS[type].parameters.reduce((acc, p) => ({...acc, [p.name]: p.default}), {})
105
  },
@@ -107,8 +122,9 @@ const AppContent = () => {
107
 
108
  setNodes((nds) => nds.concat(newNode));
109
  setSelectedNodeId(newNode.id);
 
110
  },
111
- [reactFlowInstance, setNodes]
112
  );
113
 
114
  const onNodeClick = useCallback((_: React.MouseEvent, node: Node) => {
@@ -135,20 +151,25 @@ const AppContent = () => {
135
  };
136
 
137
  const deleteNode = (id: string) => {
 
138
  setNodes((nds) => nds.filter((node) => node.id !== id));
139
  setEdges((eds) => eds.filter((edge) => edge.source !== id && edge.target !== id));
140
  setSelectedNodeId(null);
 
141
  };
142
 
143
  const handleGeneratePrompt = async () => {
144
  if (!isConnected) { setIsApiKeyModalOpen(true); return; }
145
  setIsGeneratingPrompt(true);
146
  setIsPromptViewerOpen(true);
 
147
  try {
148
  const promptText = await generateRefinedPrompt(nodes, edges);
149
  setGeneratedPrompt(promptText);
 
150
  } catch (e) {
151
  setGeneratedPrompt("Failed to generate prompt. Please try again.");
 
152
  } finally {
153
  setIsGeneratingPrompt(false);
154
  }
@@ -157,11 +178,15 @@ const AppContent = () => {
157
  const handleValidate = async () => {
158
  if (!isConnected) { setIsApiKeyModalOpen(true); return; }
159
  setValidationMsg("Validating...");
 
160
  const result = await validateArchitecture(nodes, edges);
161
  setValidationMsg(result);
162
  // Auto hide after 5 seconds ONLY if valid
163
- if (result.toLowerCase().includes("valid") && result.length < 50) {
164
  setTimeout(() => setValidationMsg(null), 5000);
 
 
 
165
  }
166
  };
167
 
@@ -182,15 +207,26 @@ const AppContent = () => {
182
  const handleImplementSuggestions = async () => {
183
  if (!suggestionsText || isImplementingSuggestions) return;
184
  setIsImplementingSuggestions(true);
 
185
  try {
186
  const result = await implementArchitectureSuggestions(nodes, edges, suggestionsText);
187
  if (result && result.nodes) {
188
- // Fix types and defaults
189
- const processedNodes = result.nodes.map((n: any) => ({
190
- ...n,
191
- type: 'custom',
192
- data: { ...n.data, label: n.data.label || n.data.type }
193
- }));
 
 
 
 
 
 
 
 
 
 
194
  const processedEdges = result.edges.map((e: any) => ({
195
  ...e, animated: true, style: { stroke: '#94a3b8' }
196
  }));
@@ -198,10 +234,12 @@ const AppContent = () => {
198
  setNodes(processedNodes);
199
  setEdges(processedEdges);
200
  setIsSuggestionsOpen(false); // Close modal on success
 
201
  }
202
  } catch (e) {
203
  console.error(e);
204
- alert("Failed to implement suggestions automatically.");
 
205
  } finally {
206
  setIsImplementingSuggestions(false);
207
  }
@@ -215,11 +253,15 @@ const AppContent = () => {
215
  navigator.clipboard.writeText(JSON.stringify(layout, null, 2));
216
  setLayoutCopied(true);
217
  setTimeout(() => setLayoutCopied(false), 2000);
 
218
  };
219
 
220
- const handleApplyAIBuild = (newNodes: any[], newEdges: any[]) => {
221
  setNodes(newNodes);
222
  setEdges(newEdges);
 
 
 
223
  };
224
 
225
  const loadTemplate = (templateKey: string) => {
@@ -247,6 +289,7 @@ const AppContent = () => {
247
  setNodes(hydratedNodes);
248
  setEdges(hydratedEdges);
249
  setIsTemplateMenuOpen(false);
 
250
  }
251
  };
252
 
@@ -326,9 +369,9 @@ const AppContent = () => {
326
  <div className="bg-slate-900/95 backdrop-blur border border-slate-700 text-slate-200 px-6 py-4 rounded-xl shadow-2xl max-w-2xl w-full flex flex-col gap-3">
327
  <div className="flex items-start gap-3">
328
  <AlertTriangle className="text-amber-500 shrink-0 mt-0.5" size={20} />
329
- <div className="flex-1">
330
  <h4 className="font-bold text-sm text-slate-300 mb-1">Validation Report</h4>
331
- <p className="text-sm whitespace-pre-wrap leading-relaxed text-slate-400">{validationMsg}</p>
332
  </div>
333
  </div>
334
 
@@ -339,7 +382,7 @@ const AppContent = () => {
339
  >
340
  Dismiss
341
  </button>
342
- {!validationMsg.toLowerCase().includes("valid") && (
343
  <button
344
  onClick={() => setIsFixerOpen(true)}
345
  className="flex items-center gap-2 px-4 py-1.5 bg-red-600 hover:bg-red-500 text-white rounded text-xs font-medium transition-colors shadow-lg shadow-red-900/20"
@@ -387,6 +430,7 @@ const AppContent = () => {
387
  onChange={updateNodeData}
388
  onDelete={deleteNode}
389
  onClose={() => setSelectedNodeId(null)}
 
390
  />
391
 
392
  <CodeViewer
 
1
 
2
+
3
  import React, { useCallback, useRef, useState, useMemo, useEffect } from 'react';
4
  import ReactFlow, {
5
  ReactFlowProvider,
 
26
  import FixerModal from './components/FixerModal';
27
  import { INITIAL_NODES, INITIAL_EDGES, LAYER_DEFINITIONS, TEMPLATES } from './constants';
28
  import { generateRefinedPrompt, validateArchitecture, getArchitectureSuggestions, getUserApiKey, implementArchitectureSuggestions } from './services/geminiService';
29
+ import { NodeData, LayerType, LogEntry } from './types';
30
 
31
  let id = 1000;
32
  const getId = () => `${id++}`;
 
62
  const [isApiKeyModalOpen, setIsApiKeyModalOpen] = useState(false);
63
  const [isConnected, setIsConnected] = useState(false);
64
 
65
+ // Activity Log State
66
+ const [logs, setLogs] = useState<LogEntry[]>([]);
67
+
68
+ const addLog = useCallback((message: string, type: 'info' | 'success' | 'warning' | 'error' = 'info') => {
69
+ setLogs(prev => [{
70
+ id: Date.now().toString() + Math.random(),
71
+ timestamp: new Date(),
72
+ message,
73
+ type
74
+ }, ...prev]);
75
+ }, []);
76
+
77
  // Load connection status on mount
78
  useEffect(() => {
79
  setIsConnected(!!getUserApiKey());
80
+ addLog('System initialized. Ready to build.', 'info');
81
+ }, [addLog]);
82
 
83
  // Define custom node types
84
  const nodeTypes = useMemo(() => ({ custom: CustomNode }), []);
 
108
  y: event.clientY,
109
  });
110
 
111
+ const label = LAYER_DEFINITIONS[type].label;
112
  const newNode: Node<NodeData> = {
113
  id: getId(),
114
  type: 'custom',
115
  position,
116
  data: {
117
+ label: label,
118
  type: type,
119
  params: LAYER_DEFINITIONS[type].parameters.reduce((acc, p) => ({...acc, [p.name]: p.default}), {})
120
  },
 
122
 
123
  setNodes((nds) => nds.concat(newNode));
124
  setSelectedNodeId(newNode.id);
125
+ addLog(`Added layer: ${label}`, 'info');
126
  },
127
+ [reactFlowInstance, setNodes, addLog]
128
  );
129
 
130
  const onNodeClick = useCallback((_: React.MouseEvent, node: Node) => {
 
151
  };
152
 
153
  const deleteNode = (id: string) => {
154
+ const node = nodes.find(n => n.id === id);
155
  setNodes((nds) => nds.filter((node) => node.id !== id));
156
  setEdges((eds) => eds.filter((edge) => edge.source !== id && edge.target !== id));
157
  setSelectedNodeId(null);
158
+ if (node) addLog(`Deleted layer: ${node.data.label}`, 'info');
159
  };
160
 
161
  const handleGeneratePrompt = async () => {
162
  if (!isConnected) { setIsApiKeyModalOpen(true); return; }
163
  setIsGeneratingPrompt(true);
164
  setIsPromptViewerOpen(true);
165
+ addLog("Generating PyTorch code prompt...", 'info');
166
  try {
167
  const promptText = await generateRefinedPrompt(nodes, edges);
168
  setGeneratedPrompt(promptText);
169
+ addLog("Code prompt generated successfully.", 'success');
170
  } catch (e) {
171
  setGeneratedPrompt("Failed to generate prompt. Please try again.");
172
+ addLog("Failed to generate prompt.", 'error');
173
  } finally {
174
  setIsGeneratingPrompt(false);
175
  }
 
178
  const handleValidate = async () => {
179
  if (!isConnected) { setIsApiKeyModalOpen(true); return; }
180
  setValidationMsg("Validating...");
181
+ addLog("Running architecture validation...", 'info');
182
  const result = await validateArchitecture(nodes, edges);
183
  setValidationMsg(result);
184
  // Auto hide after 5 seconds ONLY if valid
185
+ if (result.toLowerCase().includes("valid") && !result.toLowerCase().includes("invalid") && result.length < 50) {
186
  setTimeout(() => setValidationMsg(null), 5000);
187
+ addLog("Validation passed: Architecture is valid.", 'success');
188
+ } else {
189
+ addLog("Validation issues found.", 'warning');
190
  }
191
  };
192
 
 
207
  const handleImplementSuggestions = async () => {
208
  if (!suggestionsText || isImplementingSuggestions) return;
209
  setIsImplementingSuggestions(true);
210
+ addLog("AI Agents implementing suggestions...", 'info');
211
  try {
212
  const result = await implementArchitectureSuggestions(nodes, edges, suggestionsText);
213
  if (result && result.nodes) {
214
+ // Fix types and defaults safely
215
+ const processedNodes = result.nodes.map((n: any) => {
216
+ const data = n.data || {};
217
+ const type = data.type || n.type || 'Identity'; // Fallback type
218
+ return {
219
+ ...n,
220
+ type: 'custom',
221
+ data: {
222
+ ...data,
223
+ type: type,
224
+ label: data.label || n.label || type, // Safe fallback for label
225
+ params: data.params || {}
226
+ }
227
+ };
228
+ });
229
+
230
  const processedEdges = result.edges.map((e: any) => ({
231
  ...e, animated: true, style: { stroke: '#94a3b8' }
232
  }));
 
234
  setNodes(processedNodes);
235
  setEdges(processedEdges);
236
  setIsSuggestionsOpen(false); // Close modal on success
237
+ addLog("Implemented AI improvements.", 'success');
238
  }
239
  } catch (e) {
240
  console.error(e);
241
+ addLog("Failed to implement suggestions.", 'error');
242
+ // alert("Failed to implement suggestions automatically.");
243
  } finally {
244
  setIsImplementingSuggestions(false);
245
  }
 
253
  navigator.clipboard.writeText(JSON.stringify(layout, null, 2));
254
  setLayoutCopied(true);
255
  setTimeout(() => setLayoutCopied(false), 2000);
256
+ addLog("Layout JSON copied to clipboard.", 'info');
257
  };
258
 
259
+ const handleApplyAIBuild = (newNodes: any[], newEdges: any[], logMsg?: string) => {
260
  setNodes(newNodes);
261
  setEdges(newEdges);
262
+ if (logMsg) {
263
+ addLog(logMsg, 'success');
264
+ }
265
  };
266
 
267
  const loadTemplate = (templateKey: string) => {
 
289
  setNodes(hydratedNodes);
290
  setEdges(hydratedEdges);
291
  setIsTemplateMenuOpen(false);
292
+ addLog(`Loaded template: ${template.name}`, 'info');
293
  }
294
  };
295
 
 
369
  <div className="bg-slate-900/95 backdrop-blur border border-slate-700 text-slate-200 px-6 py-4 rounded-xl shadow-2xl max-w-2xl w-full flex flex-col gap-3">
370
  <div className="flex items-start gap-3">
371
  <AlertTriangle className="text-amber-500 shrink-0 mt-0.5" size={20} />
372
+ <div className="flex-1 min-w-0">
373
  <h4 className="font-bold text-sm text-slate-300 mb-1">Validation Report</h4>
374
+ <p className="text-sm whitespace-pre-wrap leading-relaxed text-slate-400 max-h-[50vh] overflow-y-auto scrollbar-thin scrollbar-thumb-slate-700 pr-2">{validationMsg}</p>
375
  </div>
376
  </div>
377
 
 
382
  >
383
  Dismiss
384
  </button>
385
+ {!validationMsg.toLowerCase().includes("architecture is valid") && (
386
  <button
387
  onClick={() => setIsFixerOpen(true)}
388
  className="flex items-center gap-2 px-4 py-1.5 bg-red-600 hover:bg-red-500 text-white rounded text-xs font-medium transition-colors shadow-lg shadow-red-900/20"
 
430
  onChange={updateNodeData}
431
  onDelete={deleteNode}
432
  onClose={() => setSelectedNodeId(null)}
433
+ logs={logs}
434
  />
435
 
436
  <CodeViewer