import React, { useState, useCallback, useEffect } from 'react'
import { X, Zap, TrendingUp, Brain, AlertTriangle, CheckCircle } from 'lucide-react'
/**
* MLInsightsPanel — Interactive ML features panel.
* - Sector classification: type a description → get predicted sector
* - Growth predictions: view top startups ranked by growth potential
* - MLOps health: live model status and drift alerts
*/
export default function MLInsightsPanel({ onClose, onEntityClick }) {
const [activeTab, setActiveTab] = useState('growth')
return (
{/* Header */}
{/* Tabs */}
{[
{ id: 'growth', label: 'Growth Predictions', icon: TrendingUp },
{ id: 'classify', label: 'Sector Classifier', icon: Brain },
{ id: 'health', label: 'Model Health', icon: Zap },
].map(tab => (
setActiveTab(tab.id)}
className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-2.5 text-xs font-medium transition-colors ${
activeTab === tab.id
? 'text-brand-500 border-b-2 border-brand-500 bg-brand-500/5'
: 'text-atlas-muted hover:text-atlas-text'
}`}
>
{tab.label}
))}
{/* Content */}
{activeTab === 'growth' && }
{activeTab === 'classify' && }
{activeTab === 'health' && }
)
}
// ─── Growth Predictions Tab ─────────────────────────────────────────────────
function GrowthTab({ onEntityClick }) {
const [predictions, setPredictions] = useState([])
const [loading, setLoading] = useState(false)
const [filters, setFilters] = useState({ sector: '', state: '' })
const fetchPredictions = useCallback(async () => {
setLoading(true)
try {
const params = new URLSearchParams({ limit: '15' })
if (filters.sector) params.set('sector', filters.sector)
if (filters.state) params.set('state', filters.state)
const resp = await fetch(`/api/ml/predict/growth?${params}`)
const data = await resp.json()
setPredictions(data.predictions || [])
} catch (err) {
console.error('Growth prediction failed:', err)
}
setLoading(false)
}, [filters])
useEffect(() => { fetchPredictions() }, [fetchPredictions])
return (
{/* Filters */}
setFilters(f => ({ ...f, sector: e.target.value }))}
className="flex-1 px-2 py-1.5 rounded-lg bg-atlas-surface border border-atlas-border text-xs text-atlas-text"
>
All Sectors
FinTech
AI / ML
SaaS
HealthTech
EdTech
E-Commerce
CleanTech
DeepTech
setFilters(f => ({ ...f, state: e.target.value }))}
className="flex-1 px-2 py-1.5 rounded-lg bg-atlas-surface border border-atlas-border text-xs text-atlas-text"
>
All States
Karnataka
Maharashtra
Delhi
Tamil Nadu
Telangana
Gujarat
{/* Results */}
{loading ? (
) : (
{predictions.map((p, i) => (
p.slug && onEntityClick?.(p.slug)}
className="flex items-center gap-3 p-3 rounded-xl bg-atlas-surface/50 border border-atlas-border hover:border-brand-500/30 cursor-pointer transition-all"
>
{(p.growth_score * 100).toFixed(0)}
{p.entity_name}
📍 {p.city}, {p.state}
{p.top_factor && ⭐ {p.top_factor.factor.replace('_', ' ')} }
{p.growth_label.toUpperCase()}
))}
{predictions.length === 0 && !loading && (
No predictions available for these filters.
)}
)}
)
}
// ─── Sector Classifier Tab ──────────────────────────────────────────────────
function ClassifyTab() {
const [description, setDescription] = useState('')
const [result, setResult] = useState(null)
const [loading, setLoading] = useState(false)
const classify = useCallback(async () => {
if (description.length < 10) return
setLoading(true)
try {
const resp = await fetch(`/api/ml/classify/sector?description=${encodeURIComponent(description)}&top_k=5`)
const data = await resp.json()
setResult(data)
} catch (err) {
console.error('Classification failed:', err)
}
setLoading(false)
}, [description])
const exampleDescriptions = [
"AI-powered fraud detection platform for digital banking and UPI payments",
"Online marketplace connecting farmers directly with urban consumers",
"SaaS platform for hospital management and telemedicine consultations",
"Electric vehicle charging network for tier-2 cities in India",
"Gamified coding education platform for school students",
]
return (
{/* Quick examples */}
Try an example:
{exampleDescriptions.map((desc, i) => (
setDescription(desc)}
className="text-[10px] px-2 py-1 rounded-lg bg-atlas-surface text-atlas-muted hover:text-atlas-text hover:bg-atlas-border transition-colors truncate max-w-full"
>
{desc.slice(0, 50)}...
))}
{/* Result */}
{result && (
🎯
{result.sector?.replace('_', ' ')}
Confidence: {(result.confidence * 100).toFixed(1)}%
{result.top_sectors && (
All predictions:
{result.top_sectors.map((s, i) => (
{s.sector?.replace('_', ' ')}
{(s.confidence * 100).toFixed(0)}%
))}
)}
Model: {result.model_version || 'keyword_fallback_v1'}
)}
)
}
// ─── Model Health Tab ───────────────────────────────────────────────────────
function HealthTab() {
const [health, setHealth] = useState(null)
const [drift, setDrift] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
const fetchHealth = async () => {
try {
const [hRes, dRes] = await Promise.all([
fetch('/api/ml/health'),
fetch('/api/mlops/drift/check?sample_size=50'),
])
setHealth(await hRes.json())
setDrift(await dRes.json())
} catch (err) {
console.error('Health check failed:', err)
}
setLoading(false)
}
fetchHealth()
}, [])
if (loading) {
return (
)
}
return (
{/* Model Status */}
Model Status
{health?.models && Object.entries(health.models).map(([name, info]) => (
{name.replace('_', ' ')}
{info.model || info.model_path || 'Active'}
{info.mode && ` · ${info.mode}`}
{info.loaded ? 'ACTIVE' : 'DOWN'}
))}
{/* Data Drift */}
Data Drift Detection
{drift?.summary && (
{drift.summary.recommendation === 'OK' ? (
) : (
)}
{drift.summary.recommendation === 'OK' ? 'No Drift Detected' : 'Drift Detected'}
{drift.summary.features_checked} features checked · {drift.summary.drifted_features} drifted
)}
{drift?.drift_reports?.map((report, i) => (
{report.feature.replace('_', ' ')}
{report.method}
{(report.drift_score * 100).toFixed(1)}%
))}
{/* System Info */}
🔄 Models are loaded on first request. ONNX optimization available for production.
📊 Drift checks run against reference distribution from training data.
🚀 CI/CD: GitHub Actions → test → validate → deploy to HF Spaces.
)
}