golem-flask-backend / src /components /AIArchitectPanel.tsx
mememechez's picture
Deploy final cleaned source code
ca28016
raw
history blame
38.9 kB
'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<string | null>(null);
const [workflowResult, setWorkflowResult] = useState<WorkflowResult | null>(null);
const [processingStep, setProcessingStep] = useState<string>('');
const [isNotebookOpen, setIsNotebookOpen] = useState(false);
const [trainingInfo, setTrainingInfo] = useState<{ status: 'idle'|'starting'|'started'|'error'; message?: string }>()
const [workflowId, setWorkflowId] = useState<string | null>(null);
const [workflowStatus, setWorkflowStatus] = useState<any | null>(null);
const [polling, setPolling] = useState<any | null>(null);
const [showQuestionnaire, setShowQuestionnaire] = useState(false);
const [isSubmittingQuestionnaire, setIsSubmittingQuestionnaire] = useState(false);
const [hasSubmittedQuestionnaire, setHasSubmittedQuestionnaire] = useState(false);
const [questionnaireData, setQuestionnaireData] = useState<any>(null);
const [questionnaireShownForWorkflow, setQuestionnaireShownForWorkflow] = useState<string | null>(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<Response> => {
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<string, any>) => {
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 (
<div className="w-full min-h-0 flex flex-col space-y-6 p-6 overflow-y-auto cyber-scrollbar">
{/* AI Architect Header */}
<Card className="border-blue-500/20 bg-gradient-to-r from-blue-900/20 to-purple-900/20">
<CardHeader>
<CardTitle className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<Brain className="w-8 h-8 text-blue-400" />
<span className="text-2xl">ZPE AI Architect V2</span>
<Badge variant="secondary" className="bg-blue-500/20 text-blue-300">
Full Automation Mode + Dataset Architect
</Badge>
</div>
<div className="flex items-center space-x-2">
<Badge className="bg-[#00ffe7]/20 text-[#00ffe7] border-[#00ffe7]/30">
Ultimate AI Workflow ACTIVE
</Badge>
<Button variant="outline" size="sm" onClick={clearAll}>
Clear All
</Button>
</div>
</CardTitle>
</CardHeader>
</Card>
{/* Request Input */}
<Card>
<CardHeader>
<CardTitle className="flex items-center space-x-2">
<Brain className="w-5 h-5" />
<span>Natural Language Architecture Request</span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<Textarea
placeholder={`Describe the complete AI system you want to build (full automation from data to deployment)...
Examples:
• 'I need an AI to detect anomalies in manufacturing sensor data and deploy it to production'
• 'Create a complete voice recognition system for smart home control with monitoring'
• 'Build an end-to-end computer vision model to identify plant diseases with visualization'
• 'I want an AI that recognizes my face from my webcam and bypasses my password to log in'`}
value={userRequest}
onChange={(e) => setUserRequest(e.target.value)}
rows={8}
className="resize-none overflow-y-auto cyber-scrollbar"
/>
<div className="flex items-center space-x-4">
<Button
id="genAgentsBtn"
type="button"
onClick={(e) => { e.preventDefault(); e.stopPropagation(); generateArchitecture(); }}
disabled={isGenerating}
className="relative z-50 pointer-events-auto bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700"
>
{isGenerating ? (
<>
<Zap className="w-4 h-4 mr-2 animate-spin" />
{processingStep || 'AI Agents Analyzing...'}
</>
) : (
<>
<Brain className="w-4 h-4 mr-2" />
Generate with AI Agents
</>
)}
</Button>
<div className="flex items-center space-x-2 text-sm text-muted-foreground">
<Cpu className="w-4 h-4" />
<span>ZPE Consciousness Enhanced</span>
</div>
</div>
{/* Processing Status */}
{isGenerating && processingStep && (
<Alert className="border-blue-500/20 bg-blue-500/10">
<Zap className="h-4 w-4 animate-pulse" />
<AlertDescription className="text-blue-400">
<div className="flex items-center space-x-2">
<span>{processingStep}</span>
<div className="flex space-x-1">
<div className="w-2 h-2 bg-blue-400 rounded-full animate-bounce" style={{animationDelay: '0ms'}}></div>
<div className="w-2 h-2 bg-blue-400 rounded-full animate-bounce" style={{animationDelay: '150ms'}}></div>
<div className="w-2 h-2 bg-blue-400 rounded-full animate-bounce" style={{animationDelay: '300ms'}}></div>
</div>
</div>
</AlertDescription>
</Alert>
)}
{error && (
<Alert className="border-red-500/20 bg-red-500/10">
<AlertCircle className="h-4 w-4" />
<AlertDescription className="text-red-400">
{error}
</AlertDescription>
</Alert>
)}
</CardContent>
</Card>
{/* Live Agent/Stage Progress (visible immediately) */}
{workflowStatus && (
<Card className="border-cyan-500/20 bg-cyan-500/5">
<CardHeader>
<CardTitle className="flex items-center space-x-2 text-cyan-400">
<Clock className="w-5 h-5" />
<span>Agent Workflow Progress</span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<div className="text-xs text-muted-foreground">Workflow ID: {workflowId}</div>
<div className="text-sm">Status: <span className="font-semibold">{workflowStatus.status}</span></div>
<div className="w-full h-2 bg-cyan-500/10 rounded">
<div className="h-2 bg-cyan-400 rounded transition-all duration-500" style={{ width: `${Math.min(100, workflowStatus.progress_percentage || 0)}%` }} />
</div>
<div className="space-y-3 max-h-64 overflow-auto cyber-scrollbar">
{(workflowStatus.stages || []).map((s: any, i: number) => (
<div key={i} className="space-y-1">
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2">
{s.status === 'completed' ? (
<CheckCircle className="w-4 h-4 text-green-400" />
) : s.status === 'running' ? (
<div className="w-4 h-4 rounded-full border-2 border-cyan-400 border-t-transparent animate-spin" />
) : (
<Circle className="w-4 h-4 text-muted-foreground" />
)}
<span className={s.status === 'running' ? 'text-cyan-400 font-medium' : ''}>{s.name}</span>
</div>
<span className="text-xs text-muted-foreground">{s.completed_at?.slice(11,19)}</span>
</div>
{/* Show current substep if stage is running */}
{s.status === 'running' && s.current_substep && (
<div className="ml-6 pl-2 border-l border-cyan-500/30">
<div className="flex items-center gap-2 text-xs text-cyan-400/80">
<div className="w-1.5 h-1.5 bg-cyan-400 rounded-full animate-pulse" />
<span>{s.current_substep}</span>
</div>
</div>
)}
{/* Show completed substeps */}
{s.substeps && s.substeps.length > 0 && (
<div className="ml-6 pl-2 border-l border-gray-500/30 space-y-1">
{s.substeps.map((sub: any, si: number) => (
<div key={si} className="flex items-center gap-2 text-xs text-muted-foreground">
<CheckCircle className="w-3 h-3 text-green-400/60" />
<span>{sub.name}</span>
{sub.found !== undefined && <span className="text-cyan-400">({sub.found} found)</span>}
</div>
))}
</div>
)}
</div>
))}
</div>
</CardContent>
</Card>
)}
{/* Workflow Results */}
{workflowResult && (
<>
{/* Analysis Results */}
<Card className="border-green-500/20 bg-green-500/5">
<CardHeader>
<CardTitle className="flex items-center space-x-2 text-green-400">
<CheckCircle className="w-5 h-5" />
<span>AI Analysis Complete</span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* Concise A–Z Plan Summary */}
<div className="text-sm text-muted-foreground">
End-to-end plan generated by MLE-STAR agents and your PyTorch architect: Data discovery → Data plan → Advanced prep & validation → Notebook generation → Training pipeline → Deployment hooks.
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-sm font-medium text-muted-foreground">Task Type</label>
<p className="text-lg font-semibold">{workflowResult.analysis?.task_type || 'Not specified'}</p>
</div>
<div>
<label className="text-sm font-medium text-muted-foreground">Domain</label>
<p className="text-lg font-semibold">{workflowResult.analysis?.domain || 'Not specified'}</p>
</div>
<div>
<label className="text-sm font-medium text-muted-foreground">Complexity</label>
<p className="text-lg font-semibold">{workflowResult.analysis?.complexity || 'Not specified'}</p>
</div>
<div>
<label className="text-sm font-medium text-muted-foreground">Estimated Time</label>
<p className="text-lg font-semibold">{workflowResult.analysis?.estimated_time || 'Not specified'}</p>
</div>
</div>
<div>
<label className="text-sm font-medium text-muted-foreground">Recommended Models</label>
<div className="flex flex-wrap gap-2 mt-2">
{(workflowResult.analysis?.model_suggestions || []).map((model, idx) => (
<Badge key={idx} className="bg-blue-500/20 text-blue-300">
{model}
</Badge>
))}
</div>
</div>
</CardContent>
</Card>
{/* Data Plan */}
<Card className="border-purple-500/20 bg-purple-500/5">
<CardHeader>
<CardTitle className="flex items-center space-x-2 text-purple-400">
<Database className="w-5 h-5" />
<span>Intelligent Data Plan</span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* Internet Datasets */}
{(workflowResult.data_plan?.internet_datasets?.length || 0) > 0 && (
<div>
<label className="text-sm font-medium text-muted-foreground">Available Datasets</label>
<div className="space-y-2 mt-2">
{(workflowResult.data_plan?.internet_datasets || []).map((dataset, idx) => (
<div key={idx} className="p-3 border border-purple-500/20 rounded-lg bg-purple-500/5">
<div className="flex justify-between items-start">
<div>
<h4 className="font-semibold">{dataset.name}</h4>
<p className="text-sm text-muted-foreground">{dataset.description}</p>
<p className="text-xs text-purple-400">Size: {dataset.download_size}</p>
</div>
<Button variant="outline" size="sm">
<Download className="w-4 h-4" />
</Button>
</div>
</div>
))}
</div>
</div>
)}
{/* User Data Requirements */}
{workflowResult.data_plan?.user_data_needed && (
<div>
<label className="text-sm font-medium text-muted-foreground">Personal Data Required</label>
<Alert className="border-yellow-500/20 bg-yellow-500/10 mt-2">
<AlertCircle className="h-4 w-4" />
<AlertDescription className="text-yellow-400 whitespace-pre-line">
{workflowResult.data_plan?.user_data_instructions || 'No specific instructions'}
</AlertDescription>
</Alert>
</div>
)}
{/* Pretrained Models */}
{(workflowResult.data_plan?.pretrained_models?.length || 0) > 0 && (
<div>
<label className="text-sm font-medium text-muted-foreground">Pretrained Models</label>
<div className="flex flex-wrap gap-2 mt-2">
{(workflowResult.data_plan?.pretrained_models || []).map((model, idx) => (
<Badge key={idx} className="bg-green-500/20 text-green-300">
{model.name}
</Badge>
))}
</div>
</div>
)}
{/* Preprocessing Steps */}
<div>
<label className="text-sm font-medium text-muted-foreground">Preprocessing Pipeline</label>
<div className="space-y-1 mt-2">
{(workflowResult.data_plan?.preprocessing_steps || []).map((step, idx) => (
<div key={idx} className="flex items-center space-x-2 text-sm">
<Settings className="w-4 h-4 text-blue-400" />
<span>{step}</span>
</div>
))}
</div>
</div>
</CardContent>
</Card>
{/* Training Pipeline */}
<Card className="border-orange-500/20 bg-orange-500/5">
<CardHeader>
<CardTitle className="flex items-center space-x-2 text-orange-400">
<Code2 className="w-5 h-5" />
<span>Training Pipeline Generated</span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-sm font-medium text-muted-foreground">Model Architecture</label>
<p className="text-lg font-semibold">
{typeof workflowResult.training_pipeline?.architecture === 'object'
? workflowResult.training_pipeline?.architecture?.model_name || 'Custom Architecture'
: workflowResult.training_pipeline?.architecture || 'Not specified'}
</p>
</div>
<div>
<label className="text-sm font-medium text-muted-foreground">Backbone</label>
<p className="text-lg font-semibold">{workflowResult.training_pipeline?.backbone || 'Not specified'}</p>
</div>
</div>
{/* Training Pipeline Generated section buttons */}
<div className="flex items-center gap-3">
<Button
variant="secondary"
onClick={() => {
if (workflowId) {
window.open(`${API_BASE}/api/ai-architect/notebook-html/${workflowId}`, '_blank');
}
}}
>
View Jupyter Notebook
</Button>
<Button
className="bg-green-700 hover:bg-green-800"
onClick={async () => {
if (!workflowId) return;
const res = await fetch(`${API_BASE}/api/ai-architect/start-training/${workflowId}`, { method: 'POST' });
if (!res.ok) {
const t = await res.text();
setError(`Failed to start training: ${t}`);
} else {
setProcessingStep('Starting training...');
}
}}
>
Start Training
</Button>
<Button
variant="outline"
onClick={() => { if (workflowId) window.location.href = `/deep-learning/train?workflow=${workflowId}`; }}
>
Go to Train Page
</Button>
<Button
variant="secondary"
onClick={() => { if (workflowId) window.open(`${API_BASE}/api/ai-architect/artifacts/${workflowId}/zip`, '_blank'); }}
>
Download Artifacts
</Button>
{/* New: App Builder & Deployer */}
<Button
variant="secondary"
onClick={async () => {
try {
if (!workflowId) return;
setProcessingStep('Preparing app artifacts...');
const res = await fetch(`${API_BASE}/api/app-builder/prepare-artifacts/${workflowId}`, { method: 'POST' });
const data = await res.json();
if (!res.ok) throw new Error(data?.error || 'Prepare artifacts failed');
setProcessingStep(`App prepared at ${data.app_dir}`);
} catch (e: any) {
setError(e.message);
setProcessingStep('');
}
}}
>
Prepare App
</Button>
<Button
variant="outline"
onClick={async () => {
try {
if (!workflowId) return;
setProcessingStep('Building container image...');
const res = await fetch(`${API_BASE}/api/deployer/build-image/${workflowId}`, { method: 'POST' });
const data = await res.json();
if (!res.ok) throw new Error(data?.error || 'Build image failed');
setProcessingStep(`Image build status: ${data.status}${data.image ? ' (' + data.image + ')' : ''}`);
} catch (e: any) {
setError(e.message);
setProcessingStep('');
}
}}
>
Build Image
</Button>
<Button
variant="default"
onClick={async () => {
try {
if (!workflowId) return;
setProcessingStep('Starting local container...');
const res = await fetch(`${API_BASE}/api/deployer/run-local/${workflowId}`, { method: 'POST' });
const data = await res.json();
if (!res.ok) throw new Error(data?.error || 'Run local failed');
setProcessingStep(`Local server: http://localhost:${(data.ports||[8080])[0]}/health`);
} catch (e: any) {
setError(e.message);
setProcessingStep('');
}
}}
>
Run Locally
</Button>
</div>
{trainingInfo?.status && trainingInfo.status !== 'idle' && (
<div className="mt-3 text-sm">
<span className={
trainingInfo.status === 'started' ? 'text-green-400' : trainingInfo.status === 'error' ? 'text-red-400' : 'text-muted-foreground'
}>
{trainingInfo.message}
</span>
</div>
)}
<Alert className="border-orange-500/20 bg-orange-500/10">
<CheckCircle className="h-4 w-4" />
<AlertDescription className="text-orange-400">
Complete training pipeline generated with {Object.keys(workflowResult.training_pipeline || {}).length} components:
preprocessing, training, evaluation, and deployment code.
</AlertDescription>
</Alert>
</CardContent>
</Card>
</>
)}
{/* Dataset Architect Integration Notice */}
<Card className="border-[#00ffe7]/30 bg-[#00ffe7]/5">
<CardHeader>
<CardTitle className="flex items-center space-x-2 text-[#00ffe7]">
<CheckCircle className="w-5 h-5" />
<span>Ultimate AI Workflow Integration</span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
<p className="text-[#00ffe7]/80">
The Ultimate AI Workflow Orchestrator is now FULLY ACTIVE! It provides complete automation from
prompt analysis to deployment-ready models with real datasets and Jupyter notebooks.
</p>
<div className="flex items-center space-x-2">
<Badge className="bg-[#39ff14]/20 text-[#39ff14] border-[#39ff14]/30">
<CheckCircle className="w-3 h-3 mr-1" />
Smart Prompt Analysis
</Badge>
<Badge className="bg-[#39ff14]/20 text-[#39ff14] border-[#39ff14]/30">
<CheckCircle className="w-3 h-3 mr-1" />
Real Dataset Discovery
</Badge>
<Badge className="bg-[#39ff14]/20 text-[#39ff14] border-[#39ff14]/30">
<CheckCircle className="w-3 h-3 mr-1" />
Complete Training Pipeline
</Badge>
</div>
</div>
</CardContent>
</Card>
{/* Notebook Modal */}
<Dialog open={isNotebookOpen} onOpenChange={setIsNotebookOpen}>
<DialogContent className="max-w-[90vw] w-[90vw] max-h-[90vh] h-[90vh] overflow-hidden">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<FileText className="w-4 h-4" />
{workflowResult?.jupyter_notebook?.file_name || 'Generated Notebook'}
</DialogTitle>
</DialogHeader>
{workflowId ? (
<iframe
title="Notebook Viewer"
src={`${API_BASE}/api/ai-architect/notebook-html/${workflowId}`}
className="w-full h-[80vh] rounded border"
/>
) : (
<div className="text-sm text-muted-foreground">Notebook content not available</div>
)}
</DialogContent>
</Dialog>
{/* Unified Questionnaire Modal */}
<UnifiedQuestionnaire
isOpen={showQuestionnaire}
onClose={() => {
console.log('🚪 Closing questionnaire modal');
setShowQuestionnaire(false);
setHasSubmittedQuestionnaire(true);
}}
onSubmit={handleQuestionnaireSubmit}
isSubmitting={isSubmittingQuestionnaire}
workflowId={workflowId}
questionnaireData={questionnaireData}
/>
</div>
);
}