File size: 3,505 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
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import KPICard from './KPICard';

import API_BASE_URL from '../apiConfig';

export const MaterialPredictor = () => {
    const [scans, setScans] = useState(1300);
    const [failRate, setFailRate] = useState(97);
    const [prediction, setPrediction] = useState(null);
    const [modelStatus, setModelStatus] = useState(null);

    useEffect(() => {
        axios.get(`${API_BASE_URL}/api/model/status`).then(res => {
            setModelStatus(res.data);
        }).catch(() => setModelStatus({loaded: false}));
    }, []);

    const handlePredict = async () => {
        try {
            const res = await axios.post(`${API_BASE_URL}/api/predict`, { scans, fail_rate: failRate });
            setPrediction(res.data);
        } catch(e) {
            console.error(e);
        }
    };

    if (!modelStatus) return <div>Loading...</div>;

    return (
        <div>
            <div className="glass-card predictor-header">
                <div>
                    <h3 className="predictor-title">Prediction Model</h3>
                    <p style={{margin:0, color: modelStatus.loaded ? 'var(--accent3)' : 'var(--danger)'}}>
                        {modelStatus.loaded ? 'Model loaded' : 'No model found'}
                    </p>
                </div>
                {modelStatus.loaded && (
                    <p style={{color: 'var(--text-muted)', fontFamily:'monospace'}}>
                        R² = {modelStatus.metrics.r2} | MAE = {modelStatus.metrics.mae}%
                    </p>
                )}
            </div>

            <div className="glass-card">
                <h3 className="predictor-title" style={{marginBottom: '20px'}}>Forecast Parameters</h3>
                <div className="predictor-form">
                    <div className="slider-container">
                        <label>Expected Daily Production ({scans} wafers)</label>
                        <input type="range" min="100" max="2000" step="50" value={scans} onChange={(e) => setScans(parseInt(e.target.value))} />
                    </div>
                    <div className="slider-container">
                        <label>Expected Defect Rate ({failRate}%)</label>
                        <input type="range" min="0" max="100" step="5" value={failRate} onChange={(e) => setFailRate(parseInt(e.target.value))} />
                    </div>
                </div>
                <button className="btn-primary" onClick={handlePredict}>Predict Material Needs</button>
            </div>

            {prediction && (
                <div className="glass-card prediction-result">
                    <div className="kpi-container" style={{marginBottom: 0}}>
                        <KPICard title="Daily Production" value={prediction.total_scans} subtitle="wafers" color="var(--accent)" />
                        <KPICard title="Expected Defect Rate" value={`${prediction.fail_rate}%`} subtitle={`~${Math.round((prediction.total_scans*prediction.fail_rate)/100)} defective`} color="var(--danger)" />
                        <KPICard title="Avg Waste/Wafer" value={`${prediction.avg_waste_per_wafer}%`} subtitle="per defective wafer loss" color="var(--warning)" />
                        <KPICard title="Total Daily Waste" value={`${prediction.total_daily_waste} wafers`} subtitle="total estimated loss" color="var(--danger)" />
                    </div>
                </div>
            )}
        </div>
    );
};