wuhp commited on
Commit
a93e85b
·
verified ·
1 Parent(s): f3b8c5d

Update components/Builder.tsx

Browse files
Files changed (1) hide show
  1. components/Builder.tsx +64 -10
components/Builder.tsx CHANGED
@@ -12,7 +12,7 @@ import ReactFlow, {
12
  Panel,
13
  ConnectionMode
14
  } from 'reactflow';
15
- import { FileText, CheckCircle, AlertTriangle, X, Copy, Check, Lightbulb, Key, Wrench, Menu, Activity } from 'lucide-react';
16
  import Sidebar from './Sidebar';
17
  import PropertiesPanel from './PropertiesPanel';
18
  import CustomNode from './CustomNode';
@@ -22,9 +22,18 @@ import SuggestionsModal from './SuggestionsModal';
22
  import ApiKeyModal from './ApiKeyModal';
23
  import FixerModal from './FixerModal';
24
  import { INITIAL_NODES, INITIAL_EDGES, LAYER_DEFINITIONS, TEMPLATES } from '../constants';
25
- import { generateRefinedPrompt, validateArchitecture, getArchitectureSuggestions, getUserApiKey, implementArchitectureSuggestions } from '../services/geminiService';
26
  import { NodeData, LayerType, LogEntry } from '../types';
27
 
 
 
 
 
 
 
 
 
 
28
  let id = 1000;
29
  const getId = () => `${id++}`;
30
 
@@ -68,6 +77,10 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
68
  const [isApiKeyModalOpen, setIsApiKeyModalOpen] = useState(false);
69
  const [isConnected, setIsConnected] = useState(false);
70
 
 
 
 
 
71
  // Activity Log State
72
  const [logs, setLogs] = useState<LogEntry[]>([]);
73
 
@@ -207,9 +220,9 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
207
  if (!isConnected) { setIsApiKeyModalOpen(true); return; }
208
  setIsGeneratingPrompt(true);
209
  setIsPromptViewerOpen(true);
210
- addLog("Generating PyTorch code prompt...", 'info');
211
  try {
212
- const promptText = await generateRefinedPrompt(nodes, edges);
213
  setGeneratedPrompt(promptText);
214
  addLog("Code prompt generated successfully.", 'success');
215
  } catch (e) {
@@ -223,9 +236,9 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
223
  const handleValidate = async () => {
224
  if (!isConnected) { setIsApiKeyModalOpen(true); return; }
225
  setValidationMsg("Validating...");
226
- addLog("Running architecture validation...", 'info');
227
  try {
228
- const result = await validateArchitecture(nodes, edges);
229
  setValidationMsg(result);
230
  if (result.toLowerCase().includes("valid") && !result.toLowerCase().includes("invalid") && result.length < 50) {
231
  setTimeout(() => setValidationMsg(null), 5000);
@@ -244,7 +257,7 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
244
  setIsSuggestionsOpen(true);
245
  setIsSuggestionsLoading(true);
246
  try {
247
- const suggestions = await getArchitectureSuggestions(nodes, edges);
248
  setSuggestionsText(suggestions);
249
  } catch (error) {
250
  setSuggestionsText("Failed to get suggestions. API Error.");
@@ -257,9 +270,9 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
257
  const handleImplementSuggestions = async () => {
258
  if (!suggestionsText || isImplementingSuggestions) return;
259
  setIsImplementingSuggestions(true);
260
- addLog("AI Agents implementing suggestions...", 'info');
261
  try {
262
- const result = await implementArchitectureSuggestions(nodes, edges, suggestionsText);
263
  if (result && result.nodes) {
264
  // Fix types and defaults safely
265
  const processedNodes = result.nodes.map((n: any) => {
@@ -329,8 +342,9 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
329
  }
330
  }));
331
 
332
- const hydratedEdges = clonedEdges.map((e: any) => ({
333
  ...e,
 
334
  animated: true,
335
  style: { stroke: '#94a3b8' }
336
  }));
@@ -412,6 +426,44 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
412
  <Key size={16} className={isConnected ? "text-emerald-500" : "text-slate-400"} />
413
  <span className="hidden md:inline">{isConnected ? 'Key Active' : 'Add Key'}</span>
414
  </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
  <button
416
  onClick={handleGetSuggestions}
417
  className="flex items-center gap-2 px-3 py-2 bg-slate-800/80 backdrop-blur hover:bg-slate-700 border border-slate-700 rounded-lg text-slate-200 text-xs md:text-sm font-medium transition-colors shadow-lg"
@@ -537,6 +589,7 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
537
  onClose={() => setIsAIBuilderOpen(false)}
538
  onApply={handleApplyAIBuild}
539
  currentNodes={nodes}
 
540
  />
541
 
542
  <FixerModal
@@ -546,6 +599,7 @@ const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
546
  errorMsg={validationMsg || ''}
547
  nodes={nodes}
548
  edges={edges}
 
549
  />
550
 
551
  <ApiKeyModal
 
12
  Panel,
13
  ConnectionMode
14
  } from 'reactflow';
15
+ import { FileText, CheckCircle, AlertTriangle, X, Copy, Check, Lightbulb, Key, Wrench, Menu, Activity, ChevronDown, Cpu } from 'lucide-react';
16
  import Sidebar from './Sidebar';
17
  import PropertiesPanel from './PropertiesPanel';
18
  import CustomNode from './CustomNode';
 
22
  import ApiKeyModal from './ApiKeyModal';
23
  import FixerModal from './FixerModal';
24
  import { INITIAL_NODES, INITIAL_EDGES, LAYER_DEFINITIONS, TEMPLATES } from '../constants';
25
+ import { generateRefinedPrompt, validateArchitecture, getArchitectureSuggestions, getUserApiKey, implementArchitectureSuggestions, DEFAULT_MODEL } from '../services/geminiService';
26
  import { NodeData, LayerType, LogEntry } from '../types';
27
 
28
+ const AVAILABLE_MODELS = [
29
+ { id: 'gemini-2.5-flash', name: 'Gemini 2.5 Flash', description: 'Fast & Efficient' },
30
+ { id: 'gemini-2.5-flash-lite', name: 'Gemini 2.5 Flash-Lite', description: 'Ultra-Fast & Efficient' },
31
+ { id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro', description: 'Balanced Performance' },
32
+ { id: 'gemini-3-flash-preview', name: 'Gemini 3 Flash', description: 'Next-Gen Speed' },
33
+ { id: 'gemini-3.1-flash-lite-preview', name: 'Gemini 3.1 Flash Lite', description: 'Lightweight & Fast' },
34
+ { id: 'gemini-3.1-pro-preview', name: 'Gemini 3.1 Pro', description: 'Complex Reasoning' },
35
+ ];
36
+
37
  let id = 1000;
38
  const getId = () => `${id++}`;
39
 
 
77
  const [isApiKeyModalOpen, setIsApiKeyModalOpen] = useState(false);
78
  const [isConnected, setIsConnected] = useState(false);
79
 
80
+ // Model Selection State
81
+ const [selectedModel, setSelectedModel] = useState(DEFAULT_MODEL);
82
+ const [isModelMenuOpen, setIsModelMenuOpen] = useState(false);
83
+
84
  // Activity Log State
85
  const [logs, setLogs] = useState<LogEntry[]>([]);
86
 
 
220
  if (!isConnected) { setIsApiKeyModalOpen(true); return; }
221
  setIsGeneratingPrompt(true);
222
  setIsPromptViewerOpen(true);
223
+ addLog(`Generating PyTorch code prompt using ${AVAILABLE_MODELS.find(m => m.id === selectedModel)?.name}...`, 'info');
224
  try {
225
+ const promptText = await generateRefinedPrompt(nodes, edges, selectedModel);
226
  setGeneratedPrompt(promptText);
227
  addLog("Code prompt generated successfully.", 'success');
228
  } catch (e) {
 
236
  const handleValidate = async () => {
237
  if (!isConnected) { setIsApiKeyModalOpen(true); return; }
238
  setValidationMsg("Validating...");
239
+ addLog(`Running architecture validation using ${AVAILABLE_MODELS.find(m => m.id === selectedModel)?.name}...`, 'info');
240
  try {
241
+ const result = await validateArchitecture(nodes, edges, selectedModel);
242
  setValidationMsg(result);
243
  if (result.toLowerCase().includes("valid") && !result.toLowerCase().includes("invalid") && result.length < 50) {
244
  setTimeout(() => setValidationMsg(null), 5000);
 
257
  setIsSuggestionsOpen(true);
258
  setIsSuggestionsLoading(true);
259
  try {
260
+ const suggestions = await getArchitectureSuggestions(nodes, edges, selectedModel);
261
  setSuggestionsText(suggestions);
262
  } catch (error) {
263
  setSuggestionsText("Failed to get suggestions. API Error.");
 
270
  const handleImplementSuggestions = async () => {
271
  if (!suggestionsText || isImplementingSuggestions) return;
272
  setIsImplementingSuggestions(true);
273
+ addLog(`AI Agents implementing suggestions using ${AVAILABLE_MODELS.find(m => m.id === selectedModel)?.name}...`, 'info');
274
  try {
275
+ const result = await implementArchitectureSuggestions(nodes, edges, suggestionsText, selectedModel);
276
  if (result && result.nodes) {
277
  // Fix types and defaults safely
278
  const processedNodes = result.nodes.map((n: any) => {
 
342
  }
343
  }));
344
 
345
+ const hydratedEdges = clonedEdges.map((e: any, idx: number) => ({
346
  ...e,
347
+ id: e.id || `e-template-${idx}-${Math.random().toString(36).substr(2, 4)}`,
348
  animated: true,
349
  style: { stroke: '#94a3b8' }
350
  }));
 
426
  <Key size={16} className={isConnected ? "text-emerald-500" : "text-slate-400"} />
427
  <span className="hidden md:inline">{isConnected ? 'Key Active' : 'Add Key'}</span>
428
  </button>
429
+
430
+ {/* Model Selection Button */}
431
+ <div className="relative">
432
+ <button
433
+ onClick={() => setIsModelMenuOpen(!isModelMenuOpen)}
434
+ className="flex items-center gap-2 px-3 py-2 bg-slate-800/80 backdrop-blur hover:bg-slate-700 border border-slate-700 rounded-lg text-slate-200 text-xs md:text-sm font-medium transition-colors shadow-lg"
435
+ title="Select Gemini Model"
436
+ >
437
+ <Cpu size={16} className="text-blue-400" />
438
+ <span className="hidden md:inline">{AVAILABLE_MODELS.find(m => m.id === selectedModel)?.name.split(' ')[1] || 'Model'}</span>
439
+ <ChevronDown size={14} className={`text-slate-500 transition-transform ${isModelMenuOpen ? 'rotate-180' : ''}`} />
440
+ </button>
441
+
442
+ {isModelMenuOpen && (
443
+ <div className="absolute right-0 mt-2 w-64 bg-slate-900 border border-slate-700 rounded-xl shadow-2xl z-[100] overflow-hidden animate-in fade-in slide-in-from-top-2 duration-200">
444
+ <div className="p-2">
445
+ {AVAILABLE_MODELS.map((model) => (
446
+ <button
447
+ key={model.id}
448
+ onClick={() => {
449
+ setSelectedModel(model.id);
450
+ setIsModelMenuOpen(false);
451
+ addLog(`Switched to model: ${model.name}`, 'info');
452
+ }}
453
+ className={`w-full text-left p-3 rounded-lg transition-colors ${selectedModel === model.id ? 'bg-blue-600/20 border border-blue-500/30' : 'hover:bg-slate-800 border border-transparent'}`}
454
+ >
455
+ <div className="flex items-center justify-between">
456
+ <span className={`font-semibold text-sm ${selectedModel === model.id ? 'text-blue-400' : 'text-slate-200'}`}>{model.name}</span>
457
+ {selectedModel === model.id && <Check size={14} className="text-blue-400" />}
458
+ </div>
459
+ <div className="text-xs text-slate-500 mt-0.5">{model.description}</div>
460
+ </button>
461
+ ))}
462
+ </div>
463
+ </div>
464
+ )}
465
+ </div>
466
+
467
  <button
468
  onClick={handleGetSuggestions}
469
  className="flex items-center gap-2 px-3 py-2 bg-slate-800/80 backdrop-blur hover:bg-slate-700 border border-slate-700 rounded-lg text-slate-200 text-xs md:text-sm font-medium transition-colors shadow-lg"
 
589
  onClose={() => setIsAIBuilderOpen(false)}
590
  onApply={handleApplyAIBuild}
591
  currentNodes={nodes}
592
+ selectedModel={selectedModel}
593
  />
594
 
595
  <FixerModal
 
599
  errorMsg={validationMsg || ''}
600
  nodes={nodes}
601
  edges={edges}
602
+ selectedModel={selectedModel}
603
  />
604
 
605
  <ApiKeyModal