/** * ๐Ÿค– ML Predictions - Complete Training & Results Page * * SAME AS DATAHUB: * - Select from existing files uploaded in DataHub * - Smart target column detection with auto-select * - Fast Mode (7 algorithms, 30-60s) vs Ultra Mode (20+ algorithms, 2-10min) * - Same training overlay with animated spinning icon * - Full dark/light mode support */ import React, { useState, useEffect } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import { motion } from 'framer-motion'; import { WebIDE } from '../components/WebIDE'; import { api } from '../services/api'; import { useLiveStore } from '../store/liveStore'; // Force Vite HMR reload // Force Vite HMR reload import { Brain, TrendingUp, BarChart3, AlertTriangle, CheckCircle, Target, Zap, RefreshCw, Sparkles, Award, Layers, PieChart, Activity, Play, Square, History, Database, Download, FileText, XCircle, HeartPulse, Sliders, HelpCircle, Boxes, GitBranch, Code2, Shield, ShieldCheck, Copy, Check, Presentation, ImageDown, BarChart2, Rocket } from 'lucide-react'; import PptxGenJS from 'pptxgenjs'; import ModelHistory from '@/components/automl/ModelHistory'; import DataHealthCard from '@/components/automl/DataHealthCard'; import PlaygroundTab from '@/components/automl/PlaygroundTab'; import ExplainModal from '@/components/automl/ExplainModal'; import DeployModal from '@/components/automl/DeployModal'; import apiService from '@/services/api'; import { useUserStore } from '@/store/userStore'; import { useToast } from '@/contexts/ToastContext'; import { getUserIdSync, getAuthHeadersSync } from '@/utils/userId'; interface FeatureMetadata { name: string; type: 'numeric' | 'categorical' | 'text' | 'datetime' | 'date'; min?: number | string; // number for numeric, ISO string for datetime max?: number | string; // number for numeric, ISO string for datetime mean?: number; options?: string[]; placeholder?: string; // For text/datetime inputs format?: string; // e.g. 'YYYY-MM-DD' for date columns } interface MLResult { success: boolean; task_type: string; target_column: string; best_model: { name: string; metrics: Record; reliability?: number; // 0-100 reliability score (ALL MODES) }; all_models: Array<{ name: string; metrics: Record; reliability_score?: number; // Production Intelligence: per-model reliability warning?: string; // Production Intelligence: model warnings }>; feature_importance: Array<{ feature: string; importance: number; rank: number; }>; feature_metadata?: FeatureMetadata[]; bias_reports: Array<{ type: string; description: string; severity: string; corrected: boolean; }>; insights: string[]; recommendations: string[]; charts: Record; data_summary: { rows: number; columns: number; features_engineered: number; features_used?: number; }; processing_time_seconds: number; is_nlp_task?: boolean; primary_text_col?: string; feature_columns?: string[]; cleaned_file?: string; mode?: 'traditional' | 'nlp' | 'deep_learning'; modes_trained?: string[]; modes_requested?: string[]; results_per_mode?: Record; error?: string; }>; combined_metrics?: Record; leaderboard?: Array<{ mode: string; model: string; score: number; metrics?: Record; reliability_score?: number; // Production Intelligence }>; best_overall?: { mode: string; name: string; metrics?: Record; }; pipeline?: string; was_stopped?: boolean; // PRODUCTION INTELLIGENCE - Built into ALL training modes reliability_score?: number; // Overall model reliability 0-100 validation_warnings?: string[]; // Any warnings from production validation leakage_report?: { has_leakage: boolean; severity: string; columns_removed: string[]; details: string[]; }; dataset_profile?: { size_category: string; is_imbalanced: boolean; imbalance_ratio?: number; noise_level?: number; missing_ratio?: number; }; preprocessing_steps?: string[]; warnings?: string[]; } interface FileItem { id: string; name: string; size: number; type: string; uploadedAt: string; status: 'processing' | 'completed' | 'failed'; } const MLPredictions: React.FC = () => { const { isDark } = useUserStore(); const { mlCache, setMlCache } = useLiveStore(); const toast = useToast(); const navigate = useNavigate(); const location = useLocation(); // Results state const [result, setResult] = useState(() => { // Hydrate from zustand cache if available const cached = mlCache['latest_ml_result']; if (cached) return cached; return null; }); // Automatically save to cache whenever result changes useEffect(() => { if (result) { setMlCache('latest_ml_result', result); } }, [result, setMlCache]); const [loading, setLoading] = useState(!result); const [activeTab, setActiveTab] = useState<'overview' | 'charts' | 'features' | 'predict' | 'playground' | 'history' | 'data' | 'clustering' | 'experiments'>('overview'); const [showExplainModal, setShowExplainModal] = useState(false); const [showDeployModal, setShowDeployModal] = useState(false); const [explainInputValues, setExplainInputValues] = useState>({}); const [predictionInput, setPredictionInput] = useState>({}); const [predictionResult, setPredictionResult] = useState(null); const [chartsLoading, setChartsLoading] = useState(false); const [copiedChart, setCopiedChart] = useState(null); const [exportingPPT, setExportingPPT] = useState(false); // File & Training state - SAME AS DATAHUB const [existingFiles, setExistingFiles] = useState([]); const [selectedFiles, setSelectedFiles] = useState([]); const [training, setTraining] = useState(false); const [modelAStatus, setModelAStatus] = useState('Active'); const [modelBStatus, setModelBStatus] = useState('Testing'); const promoteModelB = () => { setModelAStatus('Archived'); setModelBStatus('Active (Champion)'); }; const toggleModelA = () => { setModelAStatus(prev => prev === 'Active' ? 'Inactive' : 'Active'); }; const [ultraMode, setUltraMode] = useState(true); // Ultra AutoML (maximum accuracy) is default // Note: Production Intelligence (leakage detection, reliability scoring) is now built into ALL modes const [targetColumn, setTargetColumn] = useState(''); const [availableColumns, setAvailableColumns] = useState([]); const [progressMessage, setProgressMessage] = useState('Initializing...'); const [abortController, setAbortController] = useState(null); // Learning Type: supervised (classification/regression) or unsupervised (clustering) const [learningType, setLearningType] = useState<'supervised' | 'unsupervised'>('supervised'); // Multi-mode ML selection - users can select multiple modes simultaneously const [selectedModes, setSelectedModes] = useState>(new Set(['traditional'])); // Algorithm selection per ML type (multi-select within each mode) const [selectedAlgorithms, setSelectedAlgorithms] = useState<{ traditional: string[]; nlp: string[]; deep_learning: string[]; }>({ traditional: ['auto'], nlp: ['auto'], deep_learning: ['auto'], }); // For backward compatibility with existing code const mlType = Array.from(selectedModes)[0] || 'traditional'; const selectedAlgorithm = selectedAlgorithms[mlType]?.[0] || 'auto'; const setMlType = (type: 'traditional' | 'nlp' | 'deep_learning') => { setSelectedModes(new Set([type])); }; // Toggle mode selection (multi-select enabled) const toggleMode = (mode: 'traditional' | 'nlp' | 'deep_learning') => { const newModes = new Set(selectedModes); if (newModes.has(mode)) { if (newModes.size > 1) { // Keep at least one mode selected newModes.delete(mode); } } else { newModes.add(mode); } setSelectedModes(newModes); }; // Toggle algorithm selection within a mode const toggleAlgorithm = (mode: 'traditional' | 'nlp' | 'deep_learning', algo: string) => { setSelectedAlgorithms(prev => { const current = prev[mode]; if (algo === 'auto') { return { ...prev, [mode]: ['auto'] }; } const withoutAuto = current.filter(a => a !== 'auto'); if (current.includes(algo)) { const filtered = withoutAuto.filter(a => a !== algo); return { ...prev, [mode]: filtered.length > 0 ? filtered : ['auto'] }; } else { return { ...prev, [mode]: [...withoutAuto, algo] }; } }); }; // Select all algorithms in a mode const selectAllAlgorithms = (mode: 'traditional' | 'nlp' | 'deep_learning') => { const allAlgos = algorithmOptions[mode].filter(a => a.value !== 'auto').map(a => a.value); setSelectedAlgorithms(prev => ({ ...prev, [mode]: allAlgos })); }; // COMPREHENSIVE Algorithm Options - ALL algorithms for each mode const algorithmOptions = { traditional: [ { value: 'auto', label: '๐Ÿš€ Auto (Best Model)', description: 'Smart selection from all algorithms', category: 'auto' }, // Tree-based { value: 'random_forest', label: 'Random Forest', description: 'Ensemble of decision trees', category: 'Tree' }, { value: 'xgboost', label: 'XGBoost', description: 'Competition winner', category: 'Tree' }, { value: 'lightgbm', label: 'LightGBM', description: 'Fast gradient boosting', category: 'Tree' }, { value: 'catboost', label: 'CatBoost', description: 'Great for categories', category: 'Tree' }, { value: 'decision_tree', label: 'Decision Tree', description: 'Simple, interpretable', category: 'Tree' }, { value: 'extra_trees', label: 'Extra Trees', description: 'More random than RF', category: 'Tree' }, { value: 'gradient_boosting', label: 'Gradient Boosting', description: 'Classic boosting', category: 'Tree' }, { value: 'hist_gradient_boosting', label: 'Histogram GB', description: 'Fast for large data', category: 'Tree' }, // Linear { value: 'logistic_regression', label: 'Logistic Regression', description: 'Fast baseline', category: 'Linear' }, { value: 'ridge', label: 'Ridge Regression', description: 'L2 regularization', category: 'Linear' }, { value: 'lasso', label: 'Lasso Regression', description: 'L1 feature selection', category: 'Linear' }, { value: 'elastic_net', label: 'Elastic Net', description: 'L1+L2 combined', category: 'Linear' }, { value: 'sgd', label: 'SGD Classifier', description: 'Online learning', category: 'Linear' }, // SVM { value: 'svm_linear', label: 'SVM (Linear)', description: 'Linear kernel', category: 'SVM' }, { value: 'svm_rbf', label: 'SVM (RBF)', description: 'Non-linear kernel', category: 'SVM' }, { value: 'svm_poly', label: 'SVM (Polynomial)', description: 'Polynomial kernel', category: 'SVM' }, // K-Nearest Neighbors { value: 'knn_3', label: 'KNN (k=3)', description: 'Fast, small k', category: 'KNN' }, { value: 'knn_5', label: 'KNN (k=5)', description: 'Balanced k', category: 'KNN' }, { value: 'knn_7', label: 'KNN (k=7)', description: 'Smoother', category: 'KNN' }, { value: 'knn_weighted', label: 'KNN (Weighted)', description: 'Distance weighted', category: 'KNN' }, // Naive Bayes { value: 'gaussian_nb', label: 'Gaussian Naive Bayes', description: 'Continuous features', category: 'Naive Bayes' }, { value: 'multinomial_nb', label: 'Multinomial NB', description: 'Count data', category: 'Naive Bayes' }, { value: 'bernoulli_nb', label: 'Bernoulli NB', description: 'Binary features', category: 'Naive Bayes' }, { value: 'complement_nb', label: 'Complement NB', description: 'Imbalanced data', category: 'Naive Bayes' }, // Ensemble { value: 'adaboost', label: 'AdaBoost', description: 'Adaptive boosting', category: 'Ensemble' }, { value: 'bagging', label: 'Bagging', description: 'Bootstrap aggregating', category: 'Ensemble' }, { value: 'voting', label: 'Voting Ensemble', description: 'Multiple models vote', category: 'Ensemble' }, { value: 'stacking', label: 'Stacking', description: 'Meta-learner', category: 'Ensemble' }, // Other { value: 'lda', label: 'LDA', description: 'Linear Discriminant', category: 'Other' }, { value: 'qda', label: 'QDA', description: 'Quadratic Discriminant', category: 'Other' }, ], nlp: [ { value: 'auto', label: '๐Ÿš€ Auto (Best NLP)', description: 'Smart NLP selection', category: 'auto' }, // Text Vectorization { value: 'tfidf', label: 'TF-IDF', description: 'Term frequency-inverse doc', category: 'Vectorization' }, { value: 'bow', label: 'Bag of Words', description: 'Word count vectors', category: 'Vectorization' }, { value: 'count_vectorizer', label: 'Count Vectorizer', description: 'Raw word counts', category: 'Vectorization' }, { value: 'hashing', label: 'Hashing Vectorizer', description: 'Memory efficient', category: 'Vectorization' }, // N-grams { value: 'unigram', label: 'Unigram', description: 'Single words', category: 'N-gram' }, { value: 'bigram', label: 'Bigram', description: 'Word pairs', category: 'N-gram' }, { value: 'trigram', label: 'Trigram', description: 'Three-word sequences', category: 'N-gram' }, { value: 'char_ngram', label: 'Character N-gram', description: 'Spelling-robust', category: 'N-gram' }, // Word Embeddings { value: 'word2vec_cbow', label: 'Word2Vec (CBOW)', description: 'Context prediction', category: 'Embeddings' }, { value: 'word2vec_skipgram', label: 'Word2Vec (Skip-gram)', description: 'Word prediction', category: 'Embeddings' }, { value: 'glove', label: 'GloVe', description: 'Global vectors', category: 'Embeddings' }, { value: 'fasttext', label: 'FastText', description: 'Subword embeddings', category: 'Embeddings' }, { value: 'doc2vec', label: 'Doc2Vec', description: 'Document vectors', category: 'Embeddings' }, // Topic Modeling { value: 'lda', label: 'LDA', description: 'Topic discovery', category: 'Topic Model' }, { value: 'lsa', label: 'LSA/LSI', description: 'Latent semantics', category: 'Topic Model' }, { value: 'nmf', label: 'NMF', description: 'Non-negative matrix', category: 'Topic Model' }, // Transformers { value: 'bert', label: 'BERT', description: 'Bidirectional encoder', category: 'Transformer' }, { value: 'distilbert', label: 'DistilBERT', description: 'Lightweight BERT', category: 'Transformer' }, { value: 'roberta', label: 'RoBERTa', description: 'Robust BERT', category: 'Transformer' }, { value: 'albert', label: 'ALBERT', description: 'Efficient BERT', category: 'Transformer' }, { value: 'xlnet', label: 'XLNet', description: 'Permutation LM', category: 'Transformer' }, { value: 'electra', label: 'ELECTRA', description: 'Efficient pretraining', category: 'Transformer' }, { value: 'gpt2', label: 'GPT-2', description: 'Generative model', category: 'Transformer' }, // Sentiment Analysis { value: 'vader', label: 'VADER', description: 'Rule-based sentiment', category: 'Sentiment' }, { value: 'textblob', label: 'TextBlob', description: 'Simple NLP', category: 'Sentiment' }, // Ensembles { value: 'voting_ensemble', label: 'Voting Ensemble', description: 'Multiple classifiers', category: 'Ensemble' }, { value: 'stacking_ensemble', label: 'Stacking Ensemble', description: 'Meta-learner', category: 'Ensemble' }, { value: 'blending_ensemble', label: 'Blending Ensemble', description: 'Holdout blend', category: 'Ensemble' }, { value: 'weighted_ensemble', label: 'Weighted Ensemble', description: 'Weighted voting', category: 'Ensemble' }, ], deep_learning: [ { value: 'auto', label: '๐Ÿš€ Auto (Best NN)', description: 'Smart architecture', category: 'auto' }, // ANN - Artificial Neural Network { value: 'ann_shallow', label: 'ANN Shallow (32)', description: 'Single hidden layer', category: 'ANN' }, { value: 'ann_medium', label: 'ANN Medium (64-32)', description: 'Two layers', category: 'ANN' }, { value: 'ann_deep', label: 'ANN Deep (128-64-32)', description: 'Three layers', category: 'ANN' }, { value: 'ann_wide', label: 'ANN Wide (256-128)', description: 'Wide network', category: 'ANN' }, // MLP - Multi-Layer Perceptron { value: 'mlp_small', label: 'MLP Small (64-32)', description: 'Fast, small data', category: 'MLP' }, { value: 'mlp_medium', label: 'MLP Medium (128-64-32)', description: 'Balanced', category: 'MLP' }, { value: 'mlp_large', label: 'MLP Large (256-128-64)', description: 'Complex patterns', category: 'MLP' }, { value: 'mlp_xl', label: 'MLP XL (512-256-128)', description: 'Large scale', category: 'MLP' }, // RNN - Recurrent Neural Network { value: 'rnn_simple', label: 'RNN Simple', description: 'Basic recurrent', category: 'RNN' }, { value: 'rnn_deep', label: 'RNN Deep', description: 'Stacked RNN', category: 'RNN' }, { value: 'rnn_bidirectional', label: 'Bidirectional RNN', description: 'Both directions', category: 'RNN' }, // LSTM - Long Short-Term Memory { value: 'lstm_simple', label: 'LSTM', description: 'Long-term memory', category: 'LSTM' }, { value: 'lstm_stacked', label: 'Stacked LSTM', description: 'Multi-layer LSTM', category: 'LSTM' }, { value: 'lstm_deep', label: 'Deep LSTM', description: '3+ layer LSTM', category: 'LSTM' }, { value: 'bilstm', label: 'BiLSTM', description: 'Bidirectional LSTM', category: 'LSTM' }, { value: 'lstm_attention', label: 'LSTM + Attention', description: 'Attention mechanism', category: 'LSTM' }, // GRU - Gated Recurrent Unit { value: 'gru_simple', label: 'GRU', description: 'Simpler than LSTM', category: 'GRU' }, { value: 'gru_stacked', label: 'Stacked GRU', description: 'Multi-layer GRU', category: 'GRU' }, { value: 'bigru', label: 'BiGRU', description: 'Bidirectional GRU', category: 'GRU' }, // CNN - Convolutional Networks { value: 'cnn_1d', label: 'CNN 1D', description: '1D convolutions', category: 'CNN' }, { value: 'textcnn', label: 'TextCNN', description: 'Text classification', category: 'CNN' }, { value: 'cnn_multichannel', label: 'Multi-channel CNN', description: 'Multiple filters', category: 'CNN' }, // Transformer { value: 'transformer_encoder', label: 'Transformer Encoder', description: 'Self-attention', category: 'Transformer' }, { value: 'transformer_decoder', label: 'Transformer Decoder', description: 'Causal attention', category: 'Transformer' }, { value: 'self_attention', label: 'Self-Attention', description: 'Attention layer', category: 'Transformer' }, { value: 'multihead_attention', label: 'Multi-Head Attention', description: 'Multiple heads', category: 'Transformer' }, // Autoencoder { value: 'autoencoder', label: 'Autoencoder', description: 'Compression', category: 'Autoencoder' }, { value: 'vae', label: 'VAE', description: 'Variational', category: 'Autoencoder' }, { value: 'sparse_autoencoder', label: 'Sparse Autoencoder', description: 'Sparse features', category: 'Autoencoder' }, { value: 'denoising_autoencoder', label: 'Denoising AE', description: 'Noise robust', category: 'Autoencoder' }, // Regularization Variants { value: 'dropout_nn', label: 'Dropout NN', description: 'Dropout regularization', category: 'Regularized' }, { value: 'batchnorm_nn', label: 'BatchNorm NN', description: 'Batch normalization', category: 'Regularized' }, { value: 'layernorm_nn', label: 'LayerNorm NN', description: 'Layer normalization', category: 'Regularized' }, { value: 'l1_regularized', label: 'L1 Regularized', description: 'Lasso penalty', category: 'Regularized' }, { value: 'l2_regularized', label: 'L2 Regularized', description: 'Ridge penalty', category: 'Regularized' }, { value: 'elastic_net_nn', label: 'Elastic Net NN', description: 'L1+L2 penalty', category: 'Regularized' }, // Activation Variants { value: 'relu_nn', label: 'ReLU Network', description: 'ReLU activation', category: 'Activation' }, { value: 'leaky_relu_nn', label: 'Leaky ReLU Network', description: 'Leaky ReLU', category: 'Activation' }, { value: 'elu_nn', label: 'ELU Network', description: 'Exponential LU', category: 'Activation' }, { value: 'selu_nn', label: 'SELU Network', description: 'Self-normalizing', category: 'Activation' }, { value: 'gelu_nn', label: 'GELU Network', description: 'Gaussian Error LU', category: 'Activation' }, { value: 'swish_nn', label: 'Swish Network', description: 'Swish activation', category: 'Activation' }, { value: 'mish_nn', label: 'Mish Network', description: 'Mish activation', category: 'Activation' }, { value: 'tanh_nn', label: 'Tanh Network', description: 'Tanh activation', category: 'Activation' }, { value: 'sigmoid_nn', label: 'Sigmoid Network', description: 'Sigmoid activation', category: 'Activation' }, // Ensemble Neural Networks { value: 'bagging_nn', label: 'Bagging NN', description: 'Bootstrap aggregating', category: 'Ensemble' }, { value: 'boosting_nn', label: 'Boosting NN', description: 'Sequential learning', category: 'Ensemble' }, { value: 'snapshot_ensemble', label: 'Snapshot Ensemble', description: 'Single training', category: 'Ensemble' }, { value: 'stacked_nn', label: 'Stacked NN', description: 'Meta-learning', category: 'Ensemble' }, // Residual Networks { value: 'resnet_mlp', label: 'ResNet-MLP', description: 'Skip connections', category: 'Residual' }, { value: 'densenet_mlp', label: 'DenseNet-MLP', description: 'Dense connections', category: 'Residual' }, { value: 'highway_network', label: 'Highway Network', description: 'Gated connections', category: 'Residual' }, { value: 'mlp_bagging', label: 'MLP Bagging', description: 'Bootstrap MLPs', category: 'Ensemble' }, ], }; const [clusteringAlgorithm, setClusteringAlgorithm] = useState('auto'); const [clusterCount, setClusterCount] = useState(null); // null = auto-detect const [clusteringResult, setClusteringResult] = useState(null); // Clustering UI state const [clusterActiveTab, setClusterActiveTab] = useState<'overview' | 'charts' | 'profiles' | 'predict' | 'download'>('overview'); const [clusterPredictionInput, setClusterPredictionInput] = useState>({}); const [clusterPredictionResult, setClusterPredictionResult] = useState(null); const [clusterPredicting, setClusterPredicting] = useState(false); // WebIDE state const [showIde, setShowIde] = useState(false); const [ideFiles, setIdeFiles] = useState>({}); // Smart target column detection - SAME AS DATAHUB const detectTargetColumn = (columns: string[]): string => { const targetPatterns = [ 'target', 'label', 'class', 'y', 'output', 'result', 'prediction', 'price_range', 'price', 'category', 'status', 'type', 'outcome', 'fraud', 'churn', 'default', 'survived', 'approved', 'purchased' ]; // Check for exact/partial matches for (const pattern of targetPatterns) { for (const col of columns) { if (col.toLowerCase().includes(pattern)) { return col; } } } // Default: last column (common ML convention) return columns[columns.length - 1]; }; // Load existing files from DataHub const loadExistingFiles = async () => { try { const response = await apiService.listFiles(); const dataFiles = (response.data.files || []).filter((f: FileItem) => f.name.endsWith('.csv') || f.name.endsWith('.xlsx') || f.name.endsWith('.xls') ); setExistingFiles(dataFiles); } catch (error) { console.error('Failed to load files:', error); } }; // Fetch charts from API const fetchChartsFromAPI = async (userId: string): Promise> => { try { const response = await fetch(`/api/v2/automl/charts/${userId}`, { headers: getAuthHeadersSync() }); const data = await response.json(); if (data.success && data.charts && Object.keys(data.charts).length > 0) { try { sessionStorage.setItem(`mlCharts_${userId}`, JSON.stringify(data.charts)); } catch (e) { console.warn('[MLPredictions] Failed to cache charts'); } return data.charts; } return {}; } catch (error) { console.warn('[MLPredictions] Failed to fetch charts:', error); return {}; } }; // Load results on mount - with proper cleanup for memory leak prevention useEffect(() => { let isMounted = true; // Prevent state updates after unmount const abortCtrl = new AbortController(); const loadResults = async () => { const userId = getUserIdSync(); // CONSISTENT user ID handling const addChartsFromStorage = async (result: MLResult): Promise => { if (!result.charts || Object.keys(result.charts).length === 0) { const savedCharts = sessionStorage.getItem(`mlCharts_${userId}`); if (savedCharts) { try { result.charts = JSON.parse(savedCharts); return result; } catch (e) { } } setChartsLoading(true); const apiCharts = await fetchChartsFromAPI(userId); setChartsLoading(false); if (Object.keys(apiCharts).length > 0) { result.charts = apiCharts; } } return result; }; // ๐Ÿ”„ Sync result with active model from backend to ensure consistency const syncWithActiveModel = async (result: MLResult): Promise => { try { // First sync basic model info const response = await fetch(`/api/v2/autonomous/models/${userId}`, { headers: getAuthHeadersSync() }); const data = await response.json(); if (data.success && data.models && data.models.length > 0) { const activeModel = data.models.find((m: any) => m.is_active); if (activeModel) { // Only update best_model if NO multimode result with best_overall exists // (multimode training already has the correct best model across all modes) const hasMultimodeResult = result.best_overall || (result as any).modes_trained?.length > 0; if (!hasMultimodeResult) { result.best_model = { name: activeModel.model_name, metrics: activeModel.metrics || {} }; result.mode = activeModel.mode || 'traditional'; } result.target_column = activeModel.target_column; result.task_type = activeModel.task_type; result.feature_columns = activeModel.feature_columns || result.feature_columns; console.log('[MLPredictions] Synced with active model:', activeModel.model_name, 'hasMultimode:', hasMultimodeResult); } } // CRITICAL: Fetch feature_metadata AND charts from saved model // Use mode=auto to let backend auto-detect the best mode for multi-mode training const savedResultResponse = await fetch(`/api/v1/automl/saved-result?user_id=${userId}&mode=auto`, { headers: getAuthHeadersSync() }); const savedResult = await savedResultResponse.json(); if (savedResult.success) { // Update feature_metadata if missing if ((!result.feature_metadata || result.feature_metadata.length === 0) && savedResult.feature_metadata?.length > 0) { result.feature_metadata = savedResult.feature_metadata; console.log('[MLPredictions] Loaded feature_metadata from saved model:', savedResult.feature_metadata.length, 'features'); } // Update charts if missing or empty if ((!result.charts || Object.keys(result.charts).length === 0) && savedResult.charts && Object.keys(savedResult.charts).length > 0) { result.charts = savedResult.charts; console.log('[MLPredictions] Loaded charts from saved model:', Object.keys(savedResult.charts).length, 'charts'); // Also save to sessionStorage for faster future access try { sessionStorage.setItem(`mlCharts_${userId}`, JSON.stringify(savedResult.charts)); } catch (e) { } } // Update mode if detected if (savedResult.mode) { result.mode = savedResult.mode as 'traditional' | 'nlp' | 'deep_learning'; } // Update multi-mode specific fields if (savedResult.modes_trained) { (result as any).modes_trained = savedResult.modes_trained; } if (savedResult.best_overall) { (result as any).best_overall = savedResult.best_overall; // CRITICAL: Update best_model from best_overall (correct mode winner) result.best_model = { name: savedResult.best_overall.name || savedResult.best_overall.model || result.best_model?.name || 'Unknown', metrics: savedResult.best_overall.metrics || result.best_model?.metrics || {} }; console.log('[MLPredictions] Updated best_model from best_overall:', result.best_model.name, 'mode:', savedResult.mode); } if (savedResult.results_per_mode) { (result as any).results_per_mode = savedResult.results_per_mode; } if (savedResult.primary_text_col) { (result as any).primary_text_col = savedResult.primary_text_col; } // CRITICAL: Update data_summary if missing (for rows, columns, features display) if ((!result.data_summary || result.data_summary.rows === 0) && savedResult.data_summary) { result.data_summary = savedResult.data_summary; console.log('[MLPredictions] Loaded data_summary from saved model:', savedResult.data_summary); } // Update all_models if missing (for Models Trained count) if ((!result.all_models || result.all_models.length === 0) && savedResult.all_models?.length > 0) { result.all_models = savedResult.all_models; console.log('[MLPredictions] Loaded all_models from saved model:', savedResult.all_models.length, 'models'); } // Update leaderboard if missing if ((!result.leaderboard || result.leaderboard?.length === 0) && savedResult.leaderboard?.length > 0) { (result as any).leaderboard = savedResult.leaderboard; } // Update insights if missing (for AI Insights section) if ((!result.insights || result.insights.length === 0) && savedResult.insights?.length > 0) { result.insights = savedResult.insights; console.log('[MLPredictions] Loaded insights from saved model:', savedResult.insights.length, 'insights'); } } } catch (err) { console.warn('[MLPredictions] Could not sync with active model:', err); } return result; }; // Priority 1: Location state (fresh training - skip sync) if (location.state?.automlResult) { const navResult = location.state.automlResult; const resultWithCharts = await addChartsFromStorage(navResult); if (!isMounted) return; // Prevent state updates if unmounted setResult(resultWithCharts); setLearningType('supervised'); setActiveTab('overview'); // Reset to overview when loading results try { // Save to BOTH localStorage and sessionStorage localStorage.setItem(`mlResults_${userId}`, JSON.stringify(navResult)); localStorage.setItem(`hasMLResults_${userId}`, 'true'); // SessionStorage for current browser session (persists during navigation) sessionStorage.setItem(`mlResultsSession_${userId}`, JSON.stringify(navResult)); } catch (storageErr) { const { charts, ...lightResult } = navResult; localStorage.setItem(`mlResults_${userId}`, JSON.stringify(lightResult)); localStorage.setItem(`hasMLResults_${userId}`, 'true'); sessionStorage.setItem(`mlResultsSession_${userId}`, JSON.stringify(lightResult)); } if (resultWithCharts.charts && Object.keys(resultWithCharts.charts).length > 0) { try { sessionStorage.setItem(`mlCharts_${userId}`, JSON.stringify(resultWithCharts.charts)); } catch (e) { } } if (isMounted) setLoading(false); return; } // Priority 1.5: Check if clustering result exists in localStorage // This MUST come before backend API (Priority 2) because the backend // may return OLD supervised results that would override recent clustering const savedClustering = localStorage.getItem(`clusteringResult_${userId}`); if (savedClustering) { try { const parsedClustering = JSON.parse(savedClustering); if (parsedClustering && parsedClustering.success) { console.log('[MLPredictions] Restored clustering result from localStorage'); if (isMounted) { setClusteringResult(parsedClustering); setLearningType('unsupervised'); setClusterActiveTab('overview'); } if (isMounted) setLoading(false); return; } } catch (e) { } } // Also check sessionStorage for clustering (current session) const sessionClustering = sessionStorage.getItem(`clusteringResult_${userId}`); if (sessionClustering) { try { const parsedClustering = JSON.parse(sessionClustering); if (parsedClustering && parsedClustering.success) { console.log('[MLPredictions] Restored clustering result from sessionStorage'); if (isMounted) { setClusteringResult(parsedClustering); setLearningType('unsupervised'); setClusterActiveTab('overview'); } if (isMounted) setLoading(false); return; } } catch (e) { } } // Priority 2: Try loading from backend FIRST (persisted across logout/refresh) // This ensures data survives logout and browser refresh try { const backendResponse = await fetch(`/api/v1/automl/saved-result?user_id=${userId}&mode=auto`, { signal: abortCtrl.signal, headers: getAuthHeadersSync() }); const backendResult = await backendResponse.json(); if (backendResult.success && backendResult.best_model) { console.log('[MLPredictions] Loaded from backend API (persisted data)'); const resultWithCharts = await addChartsFromStorage(backendResult); if (!isMounted) return; setResult(resultWithCharts); setLearningType('supervised'); setActiveTab('overview'); // Reset to overview when loading results // Cache to localStorage and sessionStorage try { localStorage.setItem(`mlResults_${userId}`, JSON.stringify(backendResult)); localStorage.setItem(`hasMLResults_${userId}`, 'true'); sessionStorage.setItem(`mlResultsSession_${userId}`, JSON.stringify(backendResult)); } catch (e) {} if (isMounted) setLoading(false); return; } } catch (err) { if ((err as Error).name === 'AbortError') return; // Ignore abort errors console.warn('[MLPredictions] Backend API not available, trying localStorage:', err); } // Priority 3: SessionStorage (current browser session - navigation within app) const sessionSaved = sessionStorage.getItem(`mlResultsSession_${userId}`); if (sessionSaved) { try { let parsedSession = JSON.parse(sessionSaved); // Don't sync - use session results as-is (they're from current session) const resultWithCharts = await addChartsFromStorage(parsedSession); if (!isMounted) return; setResult(resultWithCharts); setLearningType('supervised'); setActiveTab('overview'); // Reset to overview when loading results setLoading(false); return; } catch (e) { } } // Priority 4: User-specific localStorage (sync with active model) const saved = localStorage.getItem(`mlResults_${userId}`); if (saved) { try { let parsedSaved = JSON.parse(saved); parsedSaved = await syncWithActiveModel(parsedSaved); const resultWithCharts = await addChartsFromStorage(parsedSaved); if (!isMounted) return; setResult(resultWithCharts); setLearningType('supervised'); setActiveTab('overview'); // Reset to overview when loading results setLoading(false); return; } catch (e) { } } // Priority 5: Legacy migration (sync with active model) const legacySaved = localStorage.getItem('mlResults'); if (legacySaved) { try { let parsed = JSON.parse(legacySaved); parsed = await syncWithActiveModel(parsed); const resultWithCharts = await addChartsFromStorage(parsed); if (!isMounted) return; setResult(resultWithCharts); setLearningType('supervised'); setActiveTab('overview'); // Reset to overview when loading results localStorage.setItem(`mlResults_${userId}`, legacySaved); localStorage.setItem(`hasMLResults_${userId}`, 'true'); setLoading(false); return; } catch (e) { } } // No results - load existing files await loadExistingFiles(); if (isMounted) setLoading(false); }; loadResults(); // Only override activeTab if explicitly passed in location state // Otherwise, keep the 'overview' that was set during loadResults if (location.state?.activeTab) { setActiveTab(location.state.activeTab); } else { // Reset to overview when navigating to page without explicit tab setActiveTab('overview'); } // Cleanup function to prevent memory leaks return () => { isMounted = false; abortCtrl.abort(); }; }, [location.state, location.key]); // ๐Ÿ”„ Refresh overview when model changes (rollback/delete) const handleModelChange = async () => { const userId = getUserIdSync(); try { const response = await fetch(`/api/v2/autonomous/models/${userId}`, { headers: getAuthHeadersSync() }); const data = await response.json(); if (data.success && data.models && data.models.length > 0) { const activeModel = data.models.find((m: any) => m.is_active); if (activeModel && result) { setResult({ ...result, best_model: { name: activeModel.model_name, metrics: activeModel.metrics || {} }, target_column: activeModel.target_column, task_type: activeModel.task_type, feature_columns: activeModel.feature_columns || result.feature_columns }); } } } catch (err) { console.warn('[MLPredictions] Could not refresh after model change:', err); } }; const getMetricColor = (value: number) => { if (value >= 0.9) return '#10b981'; if (value >= 0.7) return '#f59e0b'; return '#ef4444'; }; // Fetch columns from existing file - SAME AS DATAHUB const fetchColumnsFromFile = async (fileName: string) => { try { const userId = getUserIdSync(); // Fetch parsed columns safely using pandas on the backend (handles .csv and .xlsx) const fileResponse = await fetch(`/api/v1/files/${userId}/${fileName}/columns`, { headers: getAuthHeadersSync() }); if (!fileResponse.ok) return; const resData = await fileResponse.json(); if (resData.success && resData.columns) { const columns = resData.columns; setAvailableColumns(columns); const detected = detectTargetColumn(columns); setTargetColumn(detected); console.log(`๐Ÿ“Š Detected columns: ${columns.length}, Target: ${detected}`); } else { console.warn('Failed to parse columns from backend:', resData.error); } } catch (error) { console.error('Failed to fetch columns:', error); } }; // Select existing file(s) const handleSelectFile = async (file: FileItem) => { let newSelected: FileItem[]; if (selectedFiles.some(f => f.id === file.id)) { // Deselect newSelected = selectedFiles.filter(f => f.id !== file.id); } else { // Select (max 5) if (selectedFiles.length >= 5) { toast.error('You can only select up to 5 datasets.'); return; } newSelected = [...selectedFiles, file]; } setSelectedFiles(newSelected); if (newSelected.length > 0) { await fetchColumnsFromFile(newSelected[0].name); } else { setAvailableColumns([]); setTargetColumn(''); } }; // Training handler - Updated for ML Type support const handleRunAutoML = async () => { if (selectedFiles.length === 0) { toast.error('Please select at least one data file first.'); return; } setTraining(true); // Create abort controller for "Stop" functionality const controller = new AbortController(); setAbortController(controller); try { // Get the files from server and send to AutoML - SAME AS DATAHUB const userId = getUserIdSync(); const formData = new FormData(); for (const f of selectedFiles) { const fileResponse = await fetch(`/api/v1/files/${userId}/${f.name}/download`, { signal: controller.signal, headers: getAuthHeadersSync() }); if (!fileResponse.ok) throw new Error(`Failed to get file ${f.name}`); const fileBlob = await fileResponse.blob(); formData.append('files', fileBlob, f.name); } formData.append('user_id', userId); // Add target column if selected/detected if (targetColumn) { formData.append('target_column', targetColumn); } // Multi-mode training support const modes = Array.from(selectedModes); formData.append('modes', JSON.stringify(modes)); formData.append('algorithms', JSON.stringify(selectedAlgorithms)); // ๏ธ PRODUCTION INTELLIGENCE - Built into ALL modes (leakage detection, reliability scoring) let endpoint: string; // Always use multi_mode/train endpoint - production intelligence is built in endpoint = '/api/v2/automl/multi_mode/train'; // Pass selected algorithms for each mode formData.append('selected_traditional', JSON.stringify(selectedAlgorithms.traditional)); formData.append('selected_nlp', JSON.stringify(selectedAlgorithms.nlp)); formData.append('selected_deep_learning', JSON.stringify(selectedAlgorithms.deep_learning)); // Ultra mode is OPTIONAL - only if user explicitly clicked Ultra button formData.append('ultra_mode', String(ultraMode && modes.includes('traditional'))); console.log('๐Ÿš€ Training with Production Intelligence:', { modes, algorithms: selectedAlgorithms, ultraMode: ultraMode && modes.includes('traditional'), productionIntelligence: 'ENABLED (leakage detection, reliability scoring)' }); const automlResponse = await fetch(endpoint, { method: 'POST', body: formData, signal: controller.signal, headers: { 'X-User-ID': userId } }); const automlResult = await automlResponse.json(); if (automlResult.success) { // Save to localStorage with USER-SPECIFIC key for data isolation try { localStorage.setItem(`mlResults_${userId}`, JSON.stringify(automlResult)); localStorage.setItem(`hasMLResults_${userId}`, 'true'); // Persist supervised learning type (so navigation back restores correctly) localStorage.setItem(`learningType_${userId}`, 'supervised'); // Clear any stale clustering result when supervised training completes localStorage.removeItem(`clusteringResult_${userId}`); sessionStorage.removeItem(`clusteringResult_${userId}`); if (automlResult.charts) { try { sessionStorage.setItem(`mlCharts_${userId}`, JSON.stringify(automlResult.charts)); } catch (chartErr) { console.warn("Charts too large for sessionStorage"); } } } catch (e) { console.warn("Storage quota full, saving result without charts"); const { charts, ...lightResult } = automlResult; localStorage.setItem(`mlResults_${userId}`, JSON.stringify(lightResult)); localStorage.setItem(`hasMLResults_${userId}`, 'true'); } window.dispatchEvent(new CustomEvent('filesUpdated')); setResult(automlResult); } else { toast.error(`AutoML failed: ${automlResult.detail || automlResult.error || 'Unknown error'}`); } } catch (error: any) { // Handle User Stop if (error.name === 'AbortError') { return; // Silent exit on stop } console.error('AutoML error:', error); toast.error(`AutoML error: ${error.message}`); } finally { setTraining(false); setAbortController(null); } }; // Clustering handler - For UNSUPERVISED learning (no target column) const handleRunClustering = async () => { if (selectedFiles.length === 0) { toast.error('Please select a data file first.'); return; } setTraining(true); setProgressMessage('๐ŸŽฏ Starting Clustering Analysis...'); try { const userId = getUserIdSync(); const token = localStorage.getItem('access_token') || sessionStorage.getItem('access_token'); const fileId = selectedFiles.length > 0 ? (selectedFiles[0].id || selectedFiles[0].name) : ''; const response = await fetch('/api/v1/ml/clustering', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-User-ID': userId, ...(token && { 'Authorization': `Bearer ${token}` }) }, body: JSON.stringify({ file_id: fileId, user_id: userId, algorithm: clusteringAlgorithm, n_clusters: clusterCount, }) }); const clusterResult = await response.json(); if (!response.ok) { // Handle HTTP errors (4xx, 5xx) const errorMsg = clusterResult.detail || clusterResult.error || clusterResult.message || 'Server error'; toast.error(`Clustering failed: ${errorMsg}`); return; } if (clusterResult.success) { setClusteringResult(clusterResult); setClusterActiveTab('overview'); // Start with overview tab // Initialize prediction input with default values if (clusterResult.feature_columns && clusterResult.feature_stats) { const defaultInputs: Record = {}; clusterResult.feature_columns.forEach((col: string) => { const stats = clusterResult.feature_stats[col]; if (stats) { defaultInputs[col] = stats.mean?.toFixed(2) || '0'; } }); setClusterPredictionInput(defaultInputs); } // Store clustering result WITHOUT charts to avoid localStorage quota exceeded try { const { charts, ...resultWithoutCharts } = clusterResult; localStorage.setItem(`clusteringResult_${userId}`, JSON.stringify(resultWithoutCharts)); // Persist the learning type so navigation back restores correctly localStorage.setItem(`learningType_${userId}`, 'unsupervised'); // Also save to sessionStorage for faster in-session navigation restore sessionStorage.setItem(`clusteringResult_${userId}`, JSON.stringify(resultWithoutCharts)); // Clear supervised session data so it doesn't override clustering on navigation sessionStorage.removeItem(`mlResultsSession_${userId}`); } catch (storageErr) { console.warn('Could not cache clustering result:', storageErr); } toast.success(`Found ${clusterResult.n_clusters} clusters with ${(clusterResult.silhouette_score * 100).toFixed(1)}% separation score!`); } else { toast.error(`Clustering failed: ${clusterResult.error || clusterResult.detail || 'Unknown error'}`); } } catch (error: any) { console.error('Clustering error:', error); toast.error(`Clustering error: ${error.message}`); } finally { setTraining(false); } }; // Predict which cluster a new data point belongs to const handlePredictCluster = async () => { if (!clusteringResult?.model_id) { toast.error('No clustering model available. Please run clustering first.'); return; } setClusterPredicting(true); setClusterPredictionResult(null); try { const userId = getUserIdSync(); const token = localStorage.getItem('access_token') || sessionStorage.getItem('access_token'); // Convert string inputs to numbers const features: Record = {}; for (const [key, value] of Object.entries(clusterPredictionInput)) { features[key] = parseFloat(value) || 0; } const response = await fetch('/api/v1/ml/clustering/predict', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-User-ID': userId, ...(token && { 'Authorization': `Bearer ${token}` }) }, body: JSON.stringify({ user_id: userId, model_id: clusteringResult.model_id, features: features }) }); const result = await response.json(); if (result.success) { setClusterPredictionResult(result); toast.success(`Predicted: ${result.cluster_name}`); } else { toast.error(`Prediction failed: ${result.error || 'Unknown error'}`); } } catch (error: any) { console.error('Cluster prediction error:', error); toast.error(`Prediction error: ${error.message}`); } finally { setClusterPredicting(false); } }; // Combined training handler based on learning type const handleStartTraining = () => { if (learningType === 'supervised') { handleRunAutoML(); } else { handleRunClustering(); } }; // Stop Training - SAME AS DATAHUB const handleStopTraining = async () => { if (abortController) abortController.abort(); setTraining(false); // Signal Backend to Stop Permanently try { const userId = getUserIdSync(); const formData = new FormData(); formData.append('user_id', userId); await fetch('/api/v2/automl/stop_training', { method: 'POST', body: formData, headers: { 'X-User-ID': userId } }); } catch (e) { console.error("Failed to signal stop to backend", e); } }; // Animation loop for training messages - Mode-aware useEffect(() => { if (!training) return; // Get mode-specific messages const modes = Array.from(selectedModes); const isMultiMode = modes.length > 1; let messages: string[]; if (isMultiMode) { messages = [ '๐Ÿš€ Starting Multi-Mode Training...', '๐ŸŒฒ Training Traditional ML algorithms...', '๐Ÿ“ Running NLP text classification...', '๐Ÿง  Building Deep Learning models...', '๐Ÿ“Š Generating mode-specific charts...', 'โš–๏ธ Comparing cross-mode performance...', '๐Ÿ† Selecting best overall model...', ]; } else if (modes.includes('nlp')) { messages = [ '๐Ÿ“ Initializing NLP Pipeline...', '๐Ÿงน Preprocessing text data...', '๐Ÿ“Š Building TF-IDF/BOW features...', '๐Ÿ”ค Training text classifiers...', '๐Ÿ“ˆ Evaluating NLP models...', 'โ˜๏ธ Generating word clouds...', '๐Ÿ“Š Creating NLP charts...', ]; } else if (modes.includes('deep_learning')) { messages = [ '๐Ÿง  Initializing Deep Learning...', '๐Ÿ“Š Preprocessing features...', '๐Ÿ”ง Building neural network architectures...', 'โšก Training ANN/MLP models...', '๐Ÿ”„ Testing LSTM/GRU/RNN patterns...', '๐Ÿ“ˆ Evaluating network performance...', '๐Ÿ“Š Generating architecture diagrams...', ]; } else if (ultraMode) { messages = [ '๐ŸŽผ Initializing Ultra AutoML...', '๐Ÿ“Š Analyzing Dataset Profile...', '๐ŸŽฏ Meta-Learning Recommendations...', '๐Ÿ”ฌ Synthesizing 50+ Features...', '๐Ÿค– Training Classical Models...', '๐Ÿง  Training Neural Networks...', '๐Ÿ“ˆ Optimizing Hyperparameters...', 'โš–๏ธ Building Ultra Ensemble...', '๐Ÿ”ฎ Generating Explainability...', ]; } else { messages = [ '๐Ÿงน Cleaning Data (Phase 1/4)...', '๐Ÿ› ๏ธ Engineering Features (Phase 2/4)...', '๐Ÿค– Training 15+ Models (Phase 3/4)...', '๐Ÿ“ˆ Optimizing Hyperparameters...', 'โš–๏ธ Building Ensembles...', '๐Ÿ“Š Generating High-Res Charts...' ]; } let i = 0; const interval = setInterval(() => { setProgressMessage(messages[i % messages.length]); i++; }, 3500); return () => clearInterval(interval); }, [training, ultraMode, selectedModes]); // Check if data files exist const hasDataFiles = existingFiles.length > 0; // Show loading spinner if (loading) { return (

Loading ML Results...

); } // ======================================================================== // NO RESULTS - SHOW TRAINING INTERFACE (SAME AS DATAHUB) // ======================================================================== if (!result && !clusteringResult) { return (
{/* TRAINING OVERLAY - Mode-Aware for Traditional ML, NLP, Deep Learning, Combined */} {training && (() => { // Determine training mode display config const modes = Array.from(selectedModes); const isMultiMode = modes.length > 1; const isNlpOnly = modes.length === 1 && modes[0] === 'nlp'; const isDlOnly = modes.length === 1 && modes[0] === 'deep_learning'; const isTraditionalOnly = modes.length === 1 && modes[0] === 'traditional'; const isAutoMode = selectedAlgorithms.traditional.includes('auto'); // Get mode-specific colors and labels let gradientClass = 'bg-gradient-to-r from-emerald-400 via-green-400 to-cyan-400'; let bgGlow = 'bg-green-500/20'; let borderOuter = 'border-t-green-400 border-r-green-400/50 border-b-green-400/20 border-l-green-400/50'; let borderInner = 'border-b-blue-400 border-l-blue-400/50 border-t-blue-400/20 border-r-blue-400/50'; let badgeBg = 'bg-green-500/20 text-green-300'; let borderCard = 'border-green-500/30'; let title = '๐Ÿš€ Fast ML Training'; let timeLabel = 'โฑ๏ธ Fast mode: 1-3 minutes for quick results.'; let badges = [{ text: '10 Core Algorithms' }, { text: 'Quick Training' }]; // PRIORITY ORDER: Check specific modes FIRST, then Fast/Ultra for traditional auto if (isMultiMode) { // Combined multi-mode training gradientClass = 'bg-gradient-to-r from-indigo-400 via-purple-400 to-pink-400'; bgGlow = 'bg-indigo-500/20'; borderOuter = 'border-t-indigo-400 border-r-indigo-400/50 border-b-indigo-400/20 border-l-indigo-400/50'; borderInner = 'border-b-pink-400 border-l-pink-400/50 border-t-pink-400/20 border-r-pink-400/50'; badgeBg = 'bg-indigo-500/20 text-indigo-300'; borderCard = 'border-indigo-500/30'; title = '๐Ÿ”€ Combined ML Training'; timeLabel = 'โฑ๏ธ Multi-mode: 5-15 minutes for comprehensive analysis.'; badges = modes.map(m => ({ text: m === 'traditional' ? 'Traditional ML' : m === 'nlp' ? 'NLP' : 'Deep Learning' })); } else if (isNlpOnly) { // NLP only mode gradientClass = 'bg-gradient-to-r from-blue-400 via-cyan-400 to-teal-400'; bgGlow = 'bg-blue-500/20'; borderOuter = 'border-t-blue-400 border-r-blue-400/50 border-b-blue-400/20 border-l-blue-400/50'; borderInner = 'border-b-cyan-400 border-l-cyan-400/50 border-t-cyan-400/20 border-r-cyan-400/50'; badgeBg = 'bg-blue-500/20 text-blue-300'; borderCard = 'border-blue-500/30'; title = '๐Ÿ“ NLP Training'; timeLabel = 'โฑ๏ธ NLP mode: 2-5 minutes for text classification.'; badges = [{ text: 'TF-IDF/BOW' }, { text: 'Word Embeddings' }, { text: 'Text Classification' }]; } else if (isDlOnly) { // Deep Learning only mode gradientClass = 'bg-gradient-to-r from-red-400 via-orange-400 to-amber-400'; bgGlow = 'bg-red-500/20'; borderOuter = 'border-t-red-400 border-r-red-400/50 border-b-red-400/20 border-l-red-400/50'; borderInner = 'border-b-orange-400 border-l-orange-400/50 border-t-orange-400/20 border-r-orange-400/50'; badgeBg = 'bg-red-500/20 text-red-300'; borderCard = 'border-red-500/30'; title = '๐Ÿง  Deep Learning Training'; timeLabel = 'โฑ๏ธ Deep Learning: 3-10 minutes for neural networks.'; badges = [{ text: 'Neural Networks' }, { text: 'MLP/ANN' }, { text: 'Auto Architecture' }]; } else if (isTraditionalOnly && !isAutoMode) { // User selected SPECIFIC algorithms (not auto) - Traditional ML with custom selection gradientClass = 'bg-gradient-to-r from-amber-400 via-yellow-400 to-lime-400'; bgGlow = 'bg-amber-500/20'; borderOuter = 'border-t-amber-400 border-r-amber-400/50 border-b-amber-400/20 border-l-amber-400/50'; borderInner = 'border-b-lime-400 border-l-lime-400/50 border-t-lime-400/20 border-r-lime-400/50'; badgeBg = 'bg-amber-500/20 text-amber-300'; borderCard = 'border-amber-500/30'; title = '๐ŸŒฒ Traditional ML Training'; timeLabel = `โฑ๏ธ Training ${selectedAlgorithms.traditional.length} selected algorithm(s).`; badges = [{ text: `${selectedAlgorithms.traditional.length} Algorithm(s)` }, { text: 'Custom Selection' }]; } else if (isTraditionalOnly && isAutoMode && ultraMode) { // Traditional with AUTO and ULTRA mode explicitly selected gradientClass = 'bg-gradient-to-r from-purple-400 via-pink-400 to-rose-400'; bgGlow = 'bg-purple-500/20'; borderOuter = 'border-t-purple-400 border-r-purple-400/50 border-b-purple-400/20 border-l-purple-400/50'; borderInner = 'border-b-pink-400 border-l-pink-400/50 border-t-pink-400/20 border-r-pink-400/50'; badgeBg = 'bg-purple-500/20 text-purple-300'; borderCard = 'border-purple-500/30'; title = '๐ŸŽผ Ultra AutoML Training'; timeLabel = 'โฑ๏ธ Ultra mode: 3-8 minutes for maximum accuracy.'; badges = [{ text: '15+ Algorithms' }, { text: 'Ensembles' }, { text: 'Auto-Tuning' }]; } // else: Default is Fast ML Training (already set above) return (
{/* Big Animated Icon - Mode Aware Colors */}
{/* Title - Mode Aware */}

{title}

{/* Mode Details */}
{badges.map((badge, idx) => ( {idx > 0 && โ€ข} {badge.text} ))}
{/* Progress Card */}

{progressMessage}

{timeLabel}

); })()} {/* Header - SAME STYLE AS DATAHUB */}

ML Predictions

Train ML models on your data files

{/* ๐Ÿค– ML Train Button - Shows when data files exist - SAME AS DATAHUB */} {hasDataFiles && selectedFiles.length > 0 && (
{/* For Supervised: Show Fast/Ultra toggle ONLY when 'auto' is selected */} {/* Hide when user has manually selected specific algorithms */} {/* Production Intelligence (leakage detection, reliability scoring) is built into ALL modes */} {learningType === 'supervised' && mlType === 'traditional' && selectedAlgorithms.traditional.includes('auto') && (
{/* Production Intelligence indicator */}
Protected
)} {/* Train Button */}
)}
{/* File Selection Card */}

Your Data Files

{existingFiles.length > 0 ? `${existingFiles.length} file(s) available from DataHub` : 'No files found - Upload files in DataHub first'}

{existingFiles.length > 0 ? (
{existingFiles.map((file) => ( ))}
) : (

No data files found

)}
{/* Learning Type Selection - Supervised vs Unsupervised */} {availableColumns.length > 0 && (

Learning Type

Choose how the AI should learn from your data

{/* Supervised Learning */} {/* Unsupervised Learning */}
)} {/* Supervised: ML Type Selector (Traditional/NLP/Deep Learning) */} {learningType === 'supervised' && availableColumns.length > 0 && (

๐Ÿค– Select ML Modes (Multi-Select)

Combine modes for hybrid predictions โ€ข Click to toggle

{selectedModes.size} mode{selectedModes.size > 1 ? 's' : ''} selected
{/* ML Mode Cards - Multi-Select */}
{/* Traditional ML */} {/* NLP */} {/* Deep Learning */}
{/* Algorithm Selection for Selected Modes */} {Array.from(selectedModes).map((mode) => (
{mode === 'traditional' ? '๐ŸŒฒ Traditional ML Algorithms' : mode === 'nlp' ? '๐Ÿ“ NLP Techniques' : '๐Ÿง  Deep Learning Architectures'}
{/* Algorithm Grid */}
{algorithmOptions[mode].filter(a => a.value !== 'auto').map((algo) => { const isSelected = selectedAlgorithms[mode].includes(algo.value); return ( ); })}
))} {/* Training Summary + Start Button */}

๐Ÿ“Š Training Summary

โ€ข Modes: {Array.from(selectedModes).map(m => m === 'traditional' ? '๐ŸŒฒ Traditional ML' : m === 'nlp' ? '๐Ÿ“ NLP' : '๐Ÿง  Deep Learning' ).join(', ')}

โ€ข Target: {targetColumn}

{Array.from(selectedModes).map(mode => (

โ€ข {mode}: { selectedAlgorithms[mode].includes('auto') ? '๐Ÿš€ Auto (best algorithms)' : `${selectedAlgorithms[mode].length} algorithm${selectedAlgorithms[mode].length > 1 ? 's' : ''} selected` }

))}
{/* START TRAINING BUTTON - Prominent */}
{training && ( )} {!targetColumn && (

โš ๏ธ Select a target column first

)}
{/* Training Progress */} {training && (
{progressMessage}
)}
)} {/* Unsupervised: Clustering Configuration */} {learningType === 'unsupervised' && availableColumns.length > 0 && (

๐ŸŽฏ Clustering Configuration

No target column needed - AI will discover groups automatically

{/* Algorithm Selection */}
{/* Cluster Count */}
setClusterCount(e.target.value ? parseInt(e.target.value) : null)} placeholder="Auto-detect" min={2} max={20} disabled={training} className="flex-1 p-3 rounded-xl border bg-transparent outline-none focus:border-purple-500 transition-all" style={{ borderColor: 'var(--border-color)', color: 'var(--text-primary)' }} />

Leave empty to auto-detect optimal clusters

{/* Train Clustering Button */}
)} {/* ๐ŸŽฏ Target Column Selection - ONLY FOR SUPERVISED */} {learningType === 'supervised' && availableColumns.length > 0 && (

๐ŸŽฏ Target Column (What to predict)

Auto-detected: {targetColumn} โ€ข Change if needed

๐Ÿ’ก Tip: Select the column you want the model to predict (e.g., price, category, fraud)

)} {/* ๐Ÿฅ Data Health Card - Shows before training */} {selectedFiles.length > 0 && ( )} {/* Instructions when no file selected */} {selectedFiles.length === 0 && existingFiles.length > 0 && (

๐Ÿ‘† Select a file above to start training

)}
); } // ======================================================================== // RESULTS VIEW - Showing trained model results // ======================================================================== // If only clustering result exists (no supervised result), show clustering-focused view if (!result && clusteringResult) { return (
{/* Clustering Header */}

Clustering Results

Algorithm: {clusteringResult.algorithm?.toUpperCase()} {' โ€ข '} Found: {clusteringResult.n_clusters} clusters {' โ€ข '} Silhouette: {(clusteringResult.silhouette_score * 100).toFixed(1)}%

{/* Clustering Metrics */}
Clusters

{clusteringResult.n_clusters}

Silhouette Score

= 0.5 ? '#22c55e' : clusteringResult.silhouette_score >= 0.25 ? '#f59e0b' : '#ef4444' }}> {(clusteringResult.silhouette_score * 100).toFixed(1)}%

{clusteringResult.silhouette_score >= 0.5 ? 'Good' : clusteringResult.silhouette_score >= 0.25 ? 'Moderate' : 'Weak'}

Algorithm

{clusteringResult.algorithm?.toUpperCase()}

Samples

{clusteringResult.n_samples?.toLocaleString() || 'N/A'}

Features

{clusteringResult.n_features || clusteringResult.feature_columns?.length || 'N/A'}

{clusteringResult.calinski_harabasz_score && (
Calinski-Harabasz

{clusteringResult.calinski_harabasz_score.toFixed(1)}

Higher = better

)}
{/* TABS - Like Supervised */}
{[ { id: 'overview', label: 'Overview', icon: PieChart }, { id: 'charts', label: 'Visualization', icon: BarChart3 }, { id: 'profiles', label: 'Cluster Profiles', icon: Activity }, { id: 'predict', label: 'Predict Cluster', icon: Play }, { id: 'download', label: 'Download', icon: Download }, ].map((tab) => ( ))}
{/* Tab Content */} {/* OVERVIEW TAB */} {clusterActiveTab === 'overview' && (
{/* Cluster Distribution */}

Cluster Distribution

{clusteringResult.cluster_distribution && Object.entries(clusteringResult.cluster_distribution).map(([cluster, count], i) => { const total = Object.values(clusteringResult.cluster_distribution as Record).reduce((a: number, b: number) => a + b, 0); const percentage = ((count as number) / total * 100).toFixed(1); return (

{count as number}

{cluster}

{percentage}%

); })}
{/* Insights */} {clusteringResult.insights && clusteringResult.insights.length > 0 && (

AI Insights

{clusteringResult.insights.map((insight: string, i: number) => (
{insight}
))}
)}
)} {/* CHARTS TAB - Full Clustering Visualizations */} {clusterActiveTab === 'charts' && (() => { const clusterChartEntries = clusteringResult.charts ? Object.entries(clusteringResult.charts) : []; const copyClusterChart = async (base64: string, name: string) => { try { const res = await fetch(base64); const blob = await res.blob(); await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]) setCopiedChart(name); setTimeout(() => setCopiedChart(null), 2000); } catch { const w = window.open(); if (w) { w.document.write(``); } } }; const exportClusterChartsToPPT = async () => { if (clusterChartEntries.length === 0) return; setExportingPPT(true); try { const pptx = new PptxGenJS(); pptx.title = 'Clustering Charts'; pptx.author = 'DataVision AI'; pptx.layout = 'LAYOUT_WIDE'; for (const [name, b64] of clusterChartEntries) { const title = name.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); const slide = pptx.addSlide(); slide.addText(title, { x: 0.5, y: 0.2, w: '90%', h: 0.6, fontSize: 22, bold: true, color: '333333', fontFace: 'Segoe UI' }); const imgData = (b64 as string).replace(/^data:image\/\w+;base64,/, ''); slide.addImage({ data: `image/png;base64,${imgData}`, x: 0.8, y: 1.0, w: 11.5, h: 5.8, sizing: { type: 'contain', w: 11.5, h: 5.8 } }); } await pptx.writeFile({ fileName: 'Clustering_Charts.pptx' }); } catch (e) { console.error('PPT export failed:', e); } finally { setExportingPPT(false); } }; const ClusterChartCard = ({ name, label, icon, base64, description, colSpan }: { name: string; label: string; icon: React.ReactNode; base64: string; description?: string; colSpan?: boolean }) => (
{icon}

{label}

{name} {description &&

{description}

}
); return (
{clusterChartEntries.length > 0 && (

{clusterChartEntries.length} chart{clusterChartEntries.length !== 1 ? 's' : ''} generated

)} {/* Charts Grid */} {clusteringResult.charts && Object.keys(clusteringResult.charts).length > 0 ? (
{clusteringResult.charts.cluster_scatter && ( } base64={clusteringResult.charts.cluster_scatter} description={clusteringResult.pca_variance_explained ? `PCA captures ${(clusteringResult.pca_variance_explained * 100).toFixed(1)}% of data variance` : undefined} /> )} {clusteringResult.charts.elbow_method && ( } base64={clusteringResult.charts.elbow_method} description="Find optimal k where the curve bends (elbow point)" /> )} {clusteringResult.charts.silhouette_comparison && ( } base64={clusteringResult.charts.silhouette_comparison} description="Higher silhouette = better cluster separation" /> )} {clusteringResult.charts.cluster_distribution && ( } base64={clusteringResult.charts.cluster_distribution} /> )} {clusteringResult.charts.silhouette_plot && ( } base64={clusteringResult.charts.silhouette_plot} description="Per-sample silhouette coefficients by cluster" /> )} {clusteringResult.charts.cluster_heatmap && ( } base64={clusteringResult.charts.cluster_heatmap} description="Feature values at each cluster center" /> )} {clusteringResult.charts.pca_variance && ( } base64={clusteringResult.charts.pca_variance} description="Cumulative variance captured by principal components" /> )} {clusteringResult.charts.pairplot && ( } base64={clusteringResult.charts.pairplot} description="Pairwise scatter plots of top features" colSpan /> )} {clusteringResult.charts.cluster_3d && ( } base64={clusteringResult.charts.cluster_3d} description="PCA 3D scatter plot of clusters" /> )} {clusteringResult.charts.dendrogram && ( } base64={clusteringResult.charts.dendrogram} description="Hierarchical relationships between clusters" colSpan /> )} {clusteringResult.charts.tsne && ( } base64={clusteringResult.charts.tsne} description="Non-linear dimensionality reduction for cluster visualization" /> )} {clusteringResult.charts.umap && ( } base64={clusteringResult.charts.umap} description="Uniform Manifold Approximation for cluster topology" /> )} {clusteringResult.charts.boxplots && ( } base64={clusteringResult.charts.boxplots} description="Distribution of features across clusters" colSpan /> )} {clusteringResult.charts.violin_plots && ( } base64={clusteringResult.charts.violin_plots} description="Feature density distributions by cluster" colSpan /> )} {clusteringResult.charts.correlation_heatmap && ( } base64={clusteringResult.charts.correlation_heatmap} description="Feature correlation matrix" /> )} {clusteringResult.charts.radar_chart && ( } base64={clusteringResult.charts.radar_chart} description="Cluster profiles across normalized features" /> )} {clusteringResult.charts.feature_importance && ( } base64={clusteringResult.charts.feature_importance} description="Features most important for cluster separation" /> )} {clusteringResult.charts.gmm_bic_aic && ( } base64={clusteringResult.charts.gmm_bic_aic} description="Model selection criteria for GMM clustering" /> )} {clusteringResult.charts.dbscan_kdist && ( } base64={clusteringResult.charts.dbscan_kdist} description="k-distance graph for DBSCAN eps parameter selection" /> )} {clusteringResult.charts.spectral_affinity && ( } base64={clusteringResult.charts.spectral_affinity} description="Pairwise similarity matrix for spectral clustering" /> )}
) : (

No charts available. Re-run clustering to generate visualizations.

)}
); })()} {/* PROFILES TAB */} {clusterActiveTab === 'profiles' && (

Cluster Profiles

{clusteringResult.cluster_profiles ? (
{Object.entries(clusteringResult.cluster_profiles).map(([clusterName, profile]: [string, any]) => (

{clusterName}

{profile.size} samples ({profile.percentage?.toFixed(1)}%)
{profile.characteristics && Object.entries(profile.characteristics).slice(0, 8).map(([feature, stats]: [string, any]) => (

{feature}

ฮผ = {stats.mean?.toFixed(2)}

))}
))}
) : (

Cluster profiles not available. Re-run clustering to generate profiles.

)}
)} {/* PREDICT TAB */} {/* DOWNLOAD TAB */} {clusterActiveTab === 'download' && (() => { const handleClusteringDownload = async (type: 'model' | 'data' | 'code', filename: string) => { try { const userId = getUserIdSync(); const urlMap = { model: `/api/v1/ml/clustering/download-model/${userId}`, data: `/api/v1/ml/clustering/download-data/${userId}`, code: `/api/v1/ml/clustering/download-code/${userId}`, }; const response = await fetch(urlMap[type], { method: 'GET', headers: { ...getAuthHeadersSync() }, }); if (!response.ok) throw new Error(`Download failed: ${response.status} ${response.statusText}`); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; // Use filename from Content-Disposition if available const disposition = response.headers.get('Content-Disposition'); const serverFilename = disposition?.match(/filename=(.+)/)?.[1]?.replace(/"/g, ''); a.download = serverFilename || filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (err) { console.error(`Clustering ${type} download error:`, err); alert(`Download failed: ${err instanceof Error ? err.message : 'Unknown error'}`); } }; return (

Clustering Assets & Code Export

Download trained clustering model, clustered dataset, and complete unsupervised ML code.

{/* Clustering Model Download */}

Clustering Model

Download the trained clustering model (.pkl) with scaler & centroids.

{clusteringResult.algorithm?.toUpperCase()} ({clusteringResult.n_clusters} clusters)

{/* Clustered Dataset Download */}

Clustered Dataset

Data with cluster assignments, PCA components & labels.

{clusteringResult.cleaned_file || clusteringResult.labels ? ( ) : ( )}

With Cluster Labels

{/* Complete Code ZIP Download */}
NEW

Complete Code

Full clustering project with train, predict, visualize & API.

Train + Predict + Charts + API

{/* What's inside the ZIP */}

What's Inside the ZIP

{[ { file: 'clustering_model.pkl', desc: 'Trained clustering model', color: '#a855f7' }, { file: 'clustered_data.csv', desc: 'Data with cluster labels', color: '#22c55e' }, { file: 'predict_cluster.py', desc: 'Predict cluster for new data', color: '#3b82f6' }, { file: 'train_clustering.py', desc: 'Re-train clustering model', color: '#ef4444' }, { file: 'visualize_clusters.py', desc: 'Generate all clustering charts', color: '#ec4899' }, { file: 'api_server.py', desc: 'Flask REST API server', color: '#6366f1' }, { file: 'charts/', desc: 'Pre-generated training charts', color: '#f59e0b' }, { file: 'config.json', desc: 'Clustering configuration', color: '#14b8a6' }, { file: 'Dockerfile', desc: 'Docker deployment ready', color: '#0ea5e9' }, ].map((item) => (

{item.file}

{item.desc}

))}
); })()} {clusterActiveTab === 'predict' && (

Predict Cluster for New Data

Enter feature values to predict which cluster a new data point belongs to

{clusteringResult.feature_columns ? ( <>
{clusteringResult.feature_columns.map((feature: string) => { const stats = clusteringResult.feature_stats?.[feature]; return (
{stats?.type === 'categorical' && stats.categories ? ( ) : ( setClusterPredictionInput(prev => ({ ...prev, [feature]: e.target.value }))} placeholder={stats ? `Range: ${stats.min?.toFixed(1)} - ${stats.max?.toFixed(1)}` : 'Enter value'} className="w-full p-3 rounded-xl border bg-transparent outline-none focus:border-purple-500 transition-all" style={{ borderColor: 'var(--border-color)', color: 'var(--text-primary)' }} /> )} {stats &&

Mean: {stats.mean?.toFixed(2)}

}
); })}
{/* Prediction Result */} {clusterPredictionResult && (

Predicted Cluster

{clusterPredictionResult.cluster_name}

{clusterPredictionResult.confidence && (

Confidence: {(clusterPredictionResult.confidence * 100).toFixed(1)}%

)} {clusterPredictionResult.cluster_description && (

{clusterPredictionResult.cluster_description}

)}
)} ) : (

Feature information not available. Please re-run clustering.

)}
)}
); } // Supervised results view - original code // At this point, result must exist (we've handled null cases above) if (!result) { return null; // TypeScript guard - this shouldn't happen } const metrics = result.best_model?.metrics || {}; // Determine if classification or regression based on available metrics const isClassification = metrics.accuracy !== undefined || metrics.f1 !== undefined || metrics.precision !== undefined; const isRegression = metrics.r2 !== undefined || metrics.rmse !== undefined; let bestMetric: [string, number] = ['accuracy', 0]; if (metrics.accuracy !== undefined) { bestMetric = ['accuracy', metrics.accuracy]; } else if (metrics.f1 !== undefined) { bestMetric = ['f1', metrics.f1]; } else if (metrics.r2 !== undefined) { bestMetric = ['r2', metrics.r2]; } else { const entries = Object.entries(metrics); if (entries.length > 0) { bestMetric = entries[0] as [string, number]; } } const rankedFeatures = (result.feature_importance && result.feature_importance.length > 0) ? result.feature_importance : (result.feature_columns || []).map((f, i) => ({ feature: f, importance: 1 / (result.feature_columns?.length || 1), rank: i + 1 })); // Determine if this is an NLP-trained model (either single NLP or NLP in multi-mode) const isNlpMode = result.mode === 'nlp' || (result as any).modes_trained?.includes('nlp') || (result as any).results_per_mode?.nlp?.success || result.best_model?.name?.toLowerCase().includes('vectorizer') || result.best_model?.name?.toLowerCase().includes('tfidf'); // Get text column for NLP mode const nlpTextColumn = (result as any).results_per_mode?.nlp?.text_column || (result as any).primary_text_col || null; // Build inputFeatures with proper NLP support let inputFeatures: FeatureMetadata[] = (result.feature_metadata && result.feature_metadata.length > 0) ? result.feature_metadata : rankedFeatures.map(f => ({ name: f.feature, type: 'numeric' as const, min: 0, max: 100, mean: 50, options: undefined as string[] | undefined, placeholder: undefined as string | undefined })); // If NLP mode and no text input in feature_metadata, add the text column if (isNlpMode && nlpTextColumn && !inputFeatures.some(f => f.name === nlpTextColumn)) { inputFeatures = [{ name: nlpTextColumn, type: 'text', placeholder: `Enter ${nlpTextColumn} for NLP prediction...` }, ...inputFeatures.filter(f => f.name !== nlpTextColumn)]; } // If NLP mode and feature_metadata is empty, create text input if (isNlpMode && inputFeatures.length === 0 && nlpTextColumn) { inputFeatures = [{ name: nlpTextColumn, type: 'text', placeholder: `Enter ${nlpTextColumn} for NLP prediction...` }]; } return (
{/* Header */}

ML Predictions

Target: {result.target_column} {' โ€ข '} Task: {result.task_type} {' โ€ข '} {result.processing_time_seconds?.toFixed(1)}s

{/* Key Metrics - Best Model + All Metrics + Production Intelligence + Models + Features */}
Best Model

{result.best_model.name}

{bestMetric[0]?.toUpperCase()}

{isRegression && !isClassification ? (bestMetric[1] as number).toFixed(4) : `${((bestMetric[1] as number) * 100).toFixed(1)}%`}

{/* PRODUCTION INTELLIGENCE: Reliability Score Card - ALL MODES */} = 80 ? '#22c55e' : (result.reliability_score || result.best_model?.reliability || 75) >= 60 ? '#f59e0b' : '#ef4444' }} >
= 80 ? '#22c55e' : (result.reliability_score || result.best_model?.reliability || 75) >= 60 ? '#f59e0b' : '#ef4444' }} />
= 80 ? 'bg-green-500/20' : (result.reliability_score || result.best_model?.reliability || 75) >= 60 ? 'bg-amber-500/20' : 'bg-red-500/20' }`}> = 80 ? '#22c55e' : (result.reliability_score || result.best_model?.reliability || 75) >= 60 ? '#f59e0b' : '#ef4444' }} />
Reliability

= 80 ? '#22c55e' : (result.reliability_score || result.best_model?.reliability || 75) >= 60 ? '#f59e0b' : '#ef4444' }}> {(result.reliability_score || result.best_model?.reliability || 75).toFixed(0)}/100

{(result.reliability_score || result.best_model?.reliability || 75) >= 80 ? 'โœ“ Production Ready' : (result.reliability_score || result.best_model?.reliability || 75) >= 60 ? 'โš  Moderate' : 'โš  Needs Review'}

Models Trained

{result.all_models?.length || 0}

Columns

{result.data_summary?.columns || result.feature_importance?.length || 0}

{/* PRODUCTION INTELLIGENCE: Leakage & Validation Warnings Banner - ALL MODES */} {(result.leakage_report?.has_leakage || (result.validation_warnings && result.validation_warnings.length > 0)) && (

Production Intelligence Alerts

{result.leakage_report?.has_leakage && (

๐Ÿšจ Data Leakage Detected & Fixed: {result.leakage_report.columns_removed.length} column(s) removed

{result.leakage_report.columns_removed.map((col, idx) => ( {col} ))}
)} {result.validation_warnings && result.validation_warnings.length > 0 && (

โš ๏ธ Validation Warnings:

    {result.validation_warnings.map((warning, idx) => (
  • โ€ข {warning}
  • ))}
)}
)} {/* Tabs - SUPERVISED ONLY (no clustering tab) */}
{[ { id: 'overview', label: 'Overview', icon: PieChart }, { id: 'charts', label: 'ML Charts', icon: BarChart3 }, { id: 'features', label: 'Features', icon: TrendingUp }, { id: 'predict', label: 'Predict', icon: Play }, { id: 'playground', label: 'Playground', icon: Sliders }, { id: 'experiments', label: 'Experiments', icon: History }, { id: 'data', label: 'Data', icon: Database }, ].map((tab) => ( ))}
{/* Tab Content */} {activeTab === 'overview' && (
{/* Multi-Mode Results (if applicable) */} {result.results_per_mode && Object.keys(result.results_per_mode).length > 1 && (

Multi-Mode Training Results

{Object.entries(result.results_per_mode).map(([mode, modeResult]: [string, any]) => { const modeColors: Record = { 'traditional': '#22c55e', 'nlp': '#3b82f6', 'deep_learning': '#ef4444' }; const modeIcons: Record = { 'traditional': '๐ŸŒฒ', 'nlp': '๐Ÿ“', 'deep_learning': '๐Ÿง ' }; const modeLabels: Record = { 'traditional': 'Traditional ML', 'nlp': 'NLP', 'deep_learning': 'Deep Learning' }; const isBest = result.best_overall?.mode === mode; return (
{modeIcons[mode]} {modeLabels[mode]} {isBest && ( BEST )}

Model: {modeResult.best_model || modeResult.algorithm || modeResult.architecture || 'N/A'}

{modeResult.success ? (
{modeResult.metrics?.accuracy !== undefined && (
Accuracy {(modeResult.metrics.accuracy * 100).toFixed(1)}%
)} {modeResult.metrics?.precision !== undefined && (
Precision {(modeResult.metrics.precision * 100).toFixed(1)}%
)} {modeResult.metrics?.recall !== undefined && (
Recall {(modeResult.metrics.recall * 100).toFixed(1)}%
)} {modeResult.metrics?.f1 !== undefined && (
F1 Score {(modeResult.metrics.f1 * 100).toFixed(1)}%
)} {modeResult.metrics?.roc_auc !== undefined && (
ROC-AUC {(modeResult.metrics.roc_auc * 100).toFixed(1)}%
)} {modeResult.metrics?.r2 !== undefined && (
Rยฒ {(modeResult.metrics.r2 as number).toFixed(4)}
)} {modeResult.metrics?.rmse !== undefined && (
RMSE {(modeResult.metrics.rmse as number).toFixed(4)}
)} {modeResult.metrics?.mae !== undefined && (
MAE {(modeResult.metrics.mae as number).toFixed(4)}
)}
) : (

โŒ Failed

)} {modeResult.error && (

{modeResult.error}

)}
); })}
)} {/* All Models */}

All Models Performance Production Validated

{isClassification ? ( <> ) : ( <> )} {((result.leaderboard && result.leaderboard.length > 0) ? result.leaderboard : result.all_models)?.slice(0, 10).map((model: any, i: number) => { const modelName = model.model || model.name; const modeLabel = model.mode ? `[${model.mode}] ` : ''; const isBest = modelName === (result.best_overall?.name || result.best_model?.name); const m = model.metrics || {}; // Theme-aware metric colors (darker for light mode contrast) const metricColors = isDark ? { acc: '#22c55e', prec: '#3b82f6', rec: '#a855f7', f1: '#f59e0b', roc: '#ef4444', text: 'var(--text-primary)' } : { acc: '#15803d', prec: '#1d4ed8', rec: '#7e22ce', f1: '#b45309', roc: '#dc2626', text: '#0f172a' }; return ( {isClassification ? ( <> ) : ( <> )} ); })}
ModelAccuracy Precision Recall F1 ROC-AUCRยฒ MSE RMSE MAEStatus
{modeLabel}{modelName} {isBest && BEST} {m.accuracy !== undefined ? `${(m.accuracy * 100).toFixed(1)}%` : '-'} {m.precision !== undefined ? `${(m.precision * 100).toFixed(1)}%` : '-'} {m.recall !== undefined ? `${(m.recall * 100).toFixed(1)}%` : '-'} {m.f1 !== undefined ? `${(m.f1 * 100).toFixed(1)}%` : '-'} {m.roc_auc !== undefined ? `${(m.roc_auc * 100).toFixed(1)}%` : '-'}{m.r2 !== undefined ? (m.r2 as number).toFixed(4) : '-'} {m.mse !== undefined ? (m.mse as number).toFixed(4) : '-'} {m.rmse !== undefined ? (m.rmse as number).toFixed(4) : '-'} {m.mae !== undefined ? (m.mae as number).toFixed(4) : '-'} = 80 ? 'bg-green-500/20 text-green-400' : (model.reliability_score || model.reliability || 75) >= 60 ? 'bg-amber-500/20 text-amber-400' : 'bg-red-500/20 text-red-400' }`}> {model.warning ? 'โš ๏ธ' : 'โœ“'} {model.reliability_score || model.reliability || 75}
{/* Insights */}

AI Insights

{result.insights?.slice(0, 5).map((insight, i) => (

{insight}

))}
)} {activeTab === 'playground' && (

Interactive Prediction Playground

{ // For multi-mode training, use the best mode from result // or 'auto' to let backend detect if (result?.mode) return result.mode as 'traditional' | 'nlp' | 'deep_learning'; if ((result as any)?.best_overall?.mode) return (result as any).best_overall.mode; // Check modes_trained for multi-mode const modesTrained = (result as any)?.modes_trained as string[] | undefined; if (modesTrained && modesTrained.length > 0) { // Return first trained mode, preferring traditional > nlp > deep_learning if (modesTrained.includes('traditional')) return 'traditional'; if (modesTrained.includes('nlp')) return 'nlp'; if (modesTrained.includes('deep_learning')) return 'deep_learning'; } // Fallback to 'auto' to let backend auto-detect return 'auto' as any; })()} onPredictionMade={(pred) => { setPredictionResult(pred); setExplainInputValues(pred.input_values || {}); }} />
)} {activeTab === 'charts' && (() => { const chartEntries = result.charts ? Object.entries(result.charts) .filter(([chartName]) => !['cluster_scatter', 'elbow_method', 'silhouette_comparison', 'silhouette_plot', 'dendrogram', 'cluster_distribution'].includes(chartName)) : []; const copyChartToClipboard = async (base64: string, chartName: string) => { try { const res = await fetch(base64); const blob = await res.blob(); await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]); setCopiedChart(chartName); setTimeout(() => setCopiedChart(null), 2000); } catch { // fallback: open in new tab const w = window.open(); if (w) { w.document.write(``); } } }; const exportAllChartsToPPT = async () => { if (chartEntries.length === 0) return; setExportingPPT(true); try { const pptx = new PptxGenJS(); pptx.title = `ML Charts - ${result.target_column || 'Model'}`; pptx.author = 'DataVision AI'; pptx.layout = 'LAYOUT_WIDE'; for (const [chartName, chartBase64] of chartEntries) { let displayName = chartName; if (chartName.startsWith('ml_')) displayName = chartName.slice(3); else if (chartName.startsWith('nlp_')) displayName = chartName.slice(4); else if (chartName.startsWith('dl_')) displayName = chartName.slice(3); const title = displayName.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); const slide = pptx.addSlide(); slide.addText(title, { x: 0.5, y: 0.2, w: '90%', h: 0.6, fontSize: 22, bold: true, color: '333333', fontFace: 'Segoe UI' }); const imgData = (chartBase64 as string).replace(/^data:image\/\w+;base64,/, ''); slide.addImage({ data: `image/png;base64,${imgData}`, x: 0.8, y: 1.0, w: 11.5, h: 5.8, sizing: { type: 'contain', w: 11.5, h: 5.8 } }); } await pptx.writeFile({ fileName: `ML_Charts_${result.target_column || 'Model'}.pptx` }); } catch (e) { console.error('PPT export failed:', e); } finally { setExportingPPT(false); } }; return (
{/* Export toolbar */} {!chartsLoading && chartEntries.length > 0 && (

{chartEntries.length} chart{chartEntries.length !== 1 ? 's' : ''} generated

)}
{chartsLoading && (

Loading Charts...

Fetching ML visualizations from server

)} {/* Filter out clustering-specific charts from supervised view */} {!chartsLoading && chartEntries .map(([chartName, chartBase64]) => { // Format chart name: remove prefix and add mode label let displayName = chartName; let modeLabel = ''; if (chartName.startsWith('ml_')) { displayName = chartName.slice(3); modeLabel = 'Traditional ML'; } else if (chartName.startsWith('nlp_')) { displayName = chartName.slice(4); modeLabel = 'NLP'; } else if (chartName.startsWith('dl_')) { displayName = chartName.slice(3); modeLabel = 'Deep Learning'; } const formattedName = displayName.replace(/_/g, ' '); return (

{formattedName}

{modeLabel && ( {modeLabel} )}
{/* Copy chart button */}
{chartName}
); })} {!chartsLoading && chartEntries.length === 0 && (

No Charts Available

Charts may not have been generated during training.

)}
); })()} {activeTab === 'features' && (

Feature Importance Ranking {rankedFeatures.length} features

{rankedFeatures.map((f, i) => (
{f.rank || i + 1}
{f.feature}
{(f.importance * 100).toFixed(1)}%
))}
)} {activeTab === 'predict' && (

Make a Prediction with {result.best_model.name}

{inputFeatures // Filter out ID/index columns that shouldn't be user inputs .filter((meta) => { const name = meta.name.toLowerCase(); // Skip unnamed columns, index columns, and ID columns if (name.startsWith('unnamed') || name === 'index' || name === '_id') return false; // Skip pure ID columns (but keep columns like 'movie_id_rating' that might be useful) if (name === 'id') return false; return true; }) .map((meta) => { const featureName = meta.name; const lowerName = featureName.toLowerCase(); // First check if it's a text column by heuristics (PRIORITY over backend type) const textKeywords = ['text', 'content', 'body', 'email', 'review', 'description', 'summary', 'message', 'overview', 'title', 'name', 'comment', 'note', 'bio', 'abstract', 'story', 'plot', 'tagline', 'headline']; const isHeuristicText = textKeywords.some(kw => lowerName.includes(kw)); const isExplicitText = meta.type === 'text'; const isNlpTask = (result as any).is_nlp_task && (result as any).primary_text_col === featureName; // Text if: explicitly marked OR heuristic match OR NLP task primary column const isText = isExplicitText || isHeuristicText || isNlpTask; // Check for datetime type (backend may send 'date' or 'datetime') const isDatetime = meta.type === 'datetime' || meta.type === 'date'; // Only numeric if NOT a text column and NOT datetime const isNumeric = !isText && !isDatetime && meta.type === 'numeric'; const isCategorical = !isText && !isNumeric && !isDatetime && (meta.type === 'categorical' || (meta.options && meta.options.length > 0)); return (
{isText ? (