'use client'; import React, { useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { Badge } from '@/components/ui/badge'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Brain, Zap, Code2, PlayCircle, CheckCircle, AlertCircle, Clock, Cpu, TrendingUp, Download, Database, FileText, Settings, Circle } from 'lucide-react'; import quantumWeaverAPI from '@/lib/api-client'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Separator } from '@/components/ui/separator'; import { useRouter } from 'next/navigation'; import UnifiedQuestionnaire from './UnifiedQuestionnaire'; interface AnalysisResult { task_type: string; domain: string; complexity: string; estimated_time: string; model_suggestions: string[]; data_requirements: string[]; } interface DataPlan { internet_datasets: Array<{ name: string; description: string; url: string; download_size: string; }>; user_data_needed: boolean; user_data_instructions: string; pretrained_models: Array<{ name: string; description: string; }>; preprocessing_steps: string[]; } interface WorkflowResult { status: string; workflow_id: string; analysis: AnalysisResult; data_plan: DataPlan; training_pipeline: any; message: string; // Optional fields returned by backend we rely on jupyter_notebook?: { content: string; file_name?: string; visualizations?: string[]; sections?: string[]; interactive?: string[]; } | null; solution?: any; } export default function AIArchitectPanel() { const router = useRouter(); const [userRequest, setUserRequest] = useState(''); const [isGenerating, setIsGenerating] = useState(false); const [error, setError] = useState(null); const [workflowResult, setWorkflowResult] = useState(null); const [processingStep, setProcessingStep] = useState(''); const [isNotebookOpen, setIsNotebookOpen] = useState(false); const [trainingInfo, setTrainingInfo] = useState<{ status: 'idle'|'starting'|'started'|'error'; message?: string }>() const [workflowId, setWorkflowId] = useState(null); const [workflowStatus, setWorkflowStatus] = useState(null); const [polling, setPolling] = useState(null); const [showQuestionnaire, setShowQuestionnaire] = useState(false); const [isSubmittingQuestionnaire, setIsSubmittingQuestionnaire] = useState(false); const [hasSubmittedQuestionnaire, setHasSubmittedQuestionnaire] = useState(false); const [questionnaireData, setQuestionnaireData] = useState(null); const [questionnaireShownForWorkflow, setQuestionnaireShownForWorkflow] = useState(null); // Smart API base detection with fallbacks const getApiBase = () => { if (typeof window === 'undefined') return process.env.NEXT_PUBLIC_TRAINING_API_BASE || 'http://localhost:9006'; const envBase = process.env.NEXT_PUBLIC_TRAINING_API_BASE; const fallbacks = [ envBase, 'http://localhost:9006', 'http://127.0.0.1:9006', 'http://0.0.0.0:9006', (window.location && window.location.origin ? window.location.origin.replace(':9002', ':9006') : '') ].filter(Boolean); return fallbacks[0] as string; }; const API_BASE = getApiBase(); // Robust fetch that tries alternative backends with per-attempt timeout const smartFetch = async (path: string, init?: RequestInit, perAttemptTimeoutMs: number = 60000): Promise => { const candidates = [ API_BASE, 'http://127.0.0.1:9006', 'http://0.0.0.0:9006', (typeof window !== 'undefined' && window.location ? window.location.origin.replace(':9002', ':9006') : '') ].filter(Boolean) as string[]; let lastErr: any = null; for (const base of candidates) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), perAttemptTimeoutMs); try { const res = await fetch(`${base}${path}`, { ...(init || {}), signal: controller.signal }); clearTimeout(timer); return res; } catch (e: any) { clearTimeout(timer); lastErr = e; continue; } } throw lastErr || new Error('Failed to fetch from all API bases'); }; const handleViewNotebook = () => { if (!workflowResult?.jupyter_notebook) { setError('Notebook not available from backend'); return; } setIsNotebookOpen(true); }; const handleStartTraining = async () => { if (!workflowResult) return; try { setTrainingInfo({ status: 'starting', message: 'Starting training...' }); const res = await fetch(`${API_BASE}/api/ai-architect/start-training/${workflowResult.workflow_id}`, { method: 'POST' }); const data = await res.json(); if (!res.ok) { throw new Error(data?.message || 'Failed to start training'); } setTrainingInfo({ status: 'started', message: data?.message || 'Training started' }); } catch (e: any) { setTrainingInfo({ status: 'error', message: e?.message || 'Training failed' }); } }; const generateArchitecture = async () => { // Allow trigger even if input is empty; backend can prompt for details setIsGenerating(true); setError(null); setWorkflowResult(null); setProcessingStep('Analyzing your request...'); setHasSubmittedQuestionnaire(false); setShowQuestionnaire(false); setQuestionnaireData(null); setQuestionnaireShownForWorkflow(null); try { console.log('🚀 Calling Ultimate AI Workflow Orchestrator via API client...'); // Update progress steps setTimeout(() => setProcessingStep('Consulting MLE-STAR agents...'), 1000); setTimeout(() => setProcessingStep('Searching for optimal datasets...'), 2000); setTimeout(() => setProcessingStep('Generating training pipeline...'), 3000); // Hit the real backend to create and run the full workflow (A→Z) const res = await smartFetch('/api/ai-architect/create-workflow', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user_request: userRequest, workflow_type: 'full_automation', priority: 'normal' }) }, 60000); const data = await res.json(); if (!res.ok) throw new Error(data?.detail || data?.message || 'Workflow creation failed'); // Store workflowId and start polling status so the user sees the agents/stages progress setWorkflowId(data.workflow_id); // Seed immediate status so the progress card renders right away setWorkflowStatus({ workflow_id: data.workflow_id, status: 'running', current_stage: 0, stages: [], progress_percentage: 0, created_at: new Date().toISOString() } as any); setProcessingStep('Workflow started. Tracking progress...'); if (polling) clearInterval(polling); const tick = async () => { if (!data.workflow_id) return; try { const sRes = await fetch(`${API_BASE}/api/ai-architect/workflow-status/${data.workflow_id}?ts=${Date.now()}`, { headers: { 'Cache-Control': 'no-cache' }, cache: 'no-store' }); if (sRes.ok) { const status = await sRes.json(); setWorkflowStatus(status); // Show questionnaire when available and not already submitted const dp = status?.solution?.data_plan; const hasQuestionnaire = dp && ((dp.user_upload_needed === true) || (Array.isArray(dp.questionnaires) && dp.questionnaires.length > 0)); if (hasQuestionnaire && !showQuestionnaire && !hasSubmittedQuestionnaire && status.status === 'waiting_for_user_data' && questionnaireShownForWorkflow !== workflowId) { console.log('🎯 Fetching intelligent questionnaire for workflow:', workflowId); setQuestionnaireShownForWorkflow(workflowId); // Fetch questionnaire data fetchIntelligentQuestionnaire(workflowId).then(() => { setShowQuestionnaire(true); }); } // When completed, stop polling and surface final artifacts if (status.status === 'completed' || status.status === 'failed') { if (polling) clearInterval(polling); setProcessingStep(status.status === 'completed' ? 'Finalizing workflow...' : 'Workflow failed'); setWorkflowResult({ status: status.status === 'completed' ? 'success' : 'error', workflow_id: status.workflow_id, analysis: { task_type: status?.solution?.training_pipeline?.architecture?.task_type || 'unspecified', domain: status?.solution?.training_pipeline?.architecture?.domain || 'unspecified', complexity: 'unspecified', estimated_time: 'unspecified', model_suggestions: [] as string[], data_requirements: [] as string[] }, data_plan: status?.solution?.data_plan || { internet_datasets: [], user_data_needed: false, user_data_instructions: '', pretrained_models: [], preprocessing_steps: [] }, training_pipeline: status?.solution?.training_pipeline || {}, message: 'Workflow completed', jupyter_notebook: status?.solution?.jupyter_notebook || null, solution: status?.solution || {} }); setProcessingStep(''); } } } catch (e) { // swallow polling errors } }; const intervalId = setInterval(tick, 1000); setPolling(intervalId); // fire immediately so user sees first stage tick(); // Keep input so user can tweak and resubmit; do not clear request text // setUserRequest(''); } catch (error: any) { console.error('❌ AI Architect connection failed:', error); setError(`Failed to connect to AI Workflow Orchestrator: ${error.message}`); setProcessingStep(''); } finally { // Ensure the button re-enables even on failures/timeouts setIsGenerating(false); // Focus button again for immediate retry UX try { (document.querySelector('#genAgentsBtn') as HTMLButtonElement)?.focus(); } catch (err) {} } }; const clearAll = () => { setUserRequest(''); setError(null); setWorkflowResult(null); setWorkflowStatus(null); setShowQuestionnaire(false); setHasSubmittedQuestionnaire(false); setQuestionnaireData(null); setQuestionnaireShownForWorkflow(null); if (polling) clearInterval(polling); }; // Removed old submitDataModal - now using handleQuestionnaireSubmit // Removed old uploadFile function - file upload handled in UnifiedQuestionnaire const fetchIntelligentQuestionnaire = async (workflowId: string) => { try { console.log('📡 Fetching questionnaire data for workflow:', workflowId); const response = await smartFetch(`/api/ai-architect/questionnaire/${workflowId}`); if (response.ok) { const data = await response.json(); console.log('📥 Received questionnaire response:', data); if (data.status === 'available' && data.questionnaire) { console.log('✅ Setting questionnaire data:', data.questionnaire); setQuestionnaireData(data.questionnaire); return true; } else { console.warn('⚠️ No questionnaire available, using defaults'); setQuestionnaireData(null); return false; } } else { console.error('❌ Failed to fetch questionnaire, status:', response.status); setQuestionnaireData(null); return false; } } catch (error) { console.error('❌ Failed to fetch intelligent questionnaire:', error); setQuestionnaireData(null); return false; } }; const handleQuestionnaireSubmit = async (answers: Record) => { if (!workflowId) return; try { setIsSubmittingQuestionnaire(true); const response = await fetch(`${API_BASE}/api/ai-architect/submit-questionnaire`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow_id: workflowId, answers: answers }) }); if (response.ok) { const result = await response.json(); console.log('✅ Questionnaire submitted successfully:', result); // Close questionnaire modal and mark as submitted setShowQuestionnaire(false); setHasSubmittedQuestionnaire(true); setQuestionnaireData(null); console.log('🔄 Continuing workflow with answers...'); // Continue the workflow const continueResponse = await fetch(`${API_BASE}/api/ai-architect/continue-workflow/${workflowId}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(answers) }); if (continueResponse.ok) { const continueResult = await continueResponse.json(); console.log('✅ Workflow continued successfully:', continueResult); } else { console.error('❌ Failed to continue workflow:', continueResponse.statusText); } } else { throw new Error(`Failed to submit questionnaire: ${response.statusText}`); } } catch (error) { console.error('❌ Failed to submit questionnaire:', error); alert('Failed to submit questionnaire. Please try again.'); } finally { setIsSubmittingQuestionnaire(false); } }; React.useEffect(() => { const checkStatus = async () => { if (workflowId) { try { const sRes = await fetch(`${API_BASE}/api/ai-architect/workflow-status/${workflowId}?ts=${Date.now()}`, { headers: { 'Cache-Control': 'no-cache' }, cache: 'no-store' }); if (sRes.ok) { const status = await sRes.json(); setWorkflowStatus(status); // Check if we need to show the questionnaire (keep it open once shown until user acts) const dp = status?.solution?.data_plan; const hasQuestionnaire = dp && ((dp.user_upload_needed === true) || (Array.isArray(dp.questionnaires) && dp.questionnaires.length > 0)); if (hasQuestionnaire && !hasSubmittedQuestionnaire) { setShowQuestionnaire(true); } } } catch (error) { console.error('Error checking workflow status:', error); } } }; if (workflowId) { checkStatus(); const interval = setInterval(checkStatus, 3000); return () => clearInterval(interval); } }, [workflowId, workflowResult]); return (
{/* AI Architect Header */}
ZPE AI Architect V2 Full Automation Mode + Dataset Architect
Ultimate AI Workflow ACTIVE
{/* Request Input */} Natural Language Architecture Request