Spaces:
Running
Running
File size: 6,185 Bytes
a985b94 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Chart as ChartJS, ArcElement, Tooltip, Legend, CategoryScale, LinearScale, PointElement, LineElement, BarElement } from 'chart.js';
import { Pie, Bar, Line } from 'react-chartjs-2';
import KPICard from './KPICard';
import API_BASE_URL from '../apiConfig';
ChartJS.register(ArcElement, Tooltip, Legend, CategoryScale, LinearScale, PointElement, LineElement, BarElement);
const COLORS = {
accent: '#f472b6',
accent2: '#38bdf8',
accent3: '#4ade80',
danger: '#fb7185',
warning: '#fbbf24',
text: '#000000',
textMuted: '#3f3f46'
};
const DEFECT_COLORS = {
'Center': '#ef4444', 'Donut': '#f59e0b', 'Edge-Loc': '#10b981',
'Edge-Ring': '#3b82f6', 'Loc': '#8b5cf6', 'Random': '#ec4899',
'Scratch': '#06b6d4', 'Near-full': '#f97316', 'None': '#6b7280',
'Undetected': '#374151'
};
const chartOptions = {
color: COLORS.text,
plugins: {
legend: {
labels: { color: COLORS.textMuted }
}
},
scales: {
x: { ticks: { color: COLORS.textMuted }, grid: { color: 'rgba(0,0,0,0.1)' } },
y: { ticks: { color: COLORS.textMuted }, grid: { color: 'rgba(0,0,0,0.1)' } }
}
};
const pieOptions = {
color: COLORS.text,
plugins: { legend: { labels: { color: COLORS.textMuted } } }
};
export const HistoricalAnalytics = () => {
const [kpis, setKpis] = useState(null);
const [defects, setDefects] = useState(null);
const [waste, setWaste] = useState(null);
const [trends, setTrends] = useState(null);
useEffect(() => {
const fetchData = async () => {
const [kRes, dRes, wRes, tRes] = await Promise.all([
axios.get(`${API_BASE_URL}/api/kpi`),
axios.get(`${API_BASE_URL}/api/charts/defects`),
axios.get(`${API_BASE_URL}/api/charts/waste`),
axios.get(`${API_BASE_URL}/api/charts/trends`)
]);
setKpis(kRes.data);
setDefects(dRes.data);
setWaste(wRes.data);
setTrends(tRes.data);
};
fetchData();
}, []);
if (!kpis || !defects || !waste || !trends) return <div>Loading Analytics...</div>;
const pieData = {
labels: defects.predictions.map(d => d.defect_type),
datasets: [{
data: defects.predictions.map(d => d.count),
backgroundColor: defects.predictions.map(d => DEFECT_COLORS[d.defect_type] || COLORS.textMuted),
borderColor: 'transparent'
}]
};
const barData = {
labels: waste.waste_by_type.map(w => w.defect_type),
datasets: [{
label: 'Total Material Waste (Wafers)',
data: waste.waste_by_type.map(w => w.total_waste),
backgroundColor: waste.waste_by_type.map(w => DEFECT_COLORS[w.defect_type] || COLORS.textMuted)
}]
};
const trendData = {
labels: trends.dates,
datasets: [{
label: 'Fail Rate %',
data: trends.fail_rate,
borderColor: COLORS.danger,
backgroundColor: 'rgba(251, 113, 133, 0.4)',
fill: true,
yAxisID: 'y'
}]
};
const wasteTrendData = {
labels: trends.dates,
datasets: [{
label: 'Total Lost Wafers',
data: trends.waste,
borderColor: COLORS.warning,
backgroundColor: 'rgba(251, 191, 36, 0.4)',
fill: true,
yAxisID: 'y'
}]
};
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<div className="kpi-container">
<KPICard title="Total Scans" value={kpis.total_scans.toLocaleString()} subtitle="wafers inspected" color={COLORS.accent} />
<KPICard title="Pass Rate" value={`${kpis.pass_rate}%`} subtitle={`${kpis.pass_count.toLocaleString()} passed`} color={COLORS.accent3} />
<KPICard title="Fail Rate" value={`${kpis.fail_rate}%`} subtitle={`${kpis.fail_count.toLocaleString()} defective`} color={COLORS.danger} />
<KPICard title="Scrapped" value={kpis.scrap_count.toLocaleString()} subtitle="routed to scrap" color={COLORS.warning} />
<KPICard title="Avg Waste/Wafer" value={`${kpis.avg_waste}%`} subtitle="per defective wafer" color={COLORS.danger} />
<KPICard title="Avg Confidence" value={kpis.avg_confidence} subtitle="model certainty" color={COLORS.accent3} />
</div>
<div className="charts-master-grid">
<div className="glass-card chart-card">
<h3 style={{marginTop:0, marginBottom: '8px', fontSize: '14px'}}>YOLOv8 Predicted Distributions</h3>
<div className="canvas-container">
<Pie data={pieData} options={{...pieOptions, maintainAspectRatio: false}} />
</div>
</div>
<div className="glass-card chart-card">
<h3 style={{marginTop:0, marginBottom: '8px', fontSize: '14px'}}>Total Material Waste by Predict Defect</h3>
<div className="canvas-container">
<Bar data={barData} options={{...chartOptions, maintainAspectRatio: false}} />
</div>
</div>
<div className="glass-card chart-card">
<h3 style={{marginTop:0, marginBottom: '8px', fontSize: '14px'}}>Daily Defect Rate Over Time</h3>
<div className="canvas-container">
<Line data={trendData} options={{...chartOptions, maintainAspectRatio: false}} />
</div>
</div>
<div className="glass-card chart-card">
<h3 style={{marginTop:0, marginBottom: '8px', fontSize: '14px'}}>Daily Material Waste Over Time</h3>
<div className="canvas-container">
<Line data={wasteTrendData} options={{...chartOptions, maintainAspectRatio: false}} />
</div>
</div>
</div>
</div>
);
};
|