herbaguard / App.js
HerbaLensModel's picture
Upload 6 files
d66d1b5 verified
Raw
History Blame Contribute Delete
10.7 kB
import React, { useState, useEffect } from 'react';
import './App.css';
function App() {
const [modelInfo, setModelInfo] = useState(null);
const [trainingMetrics, setTrainingMetrics] = useState(null);
const [prediction, setPrediction] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// Form data for prediction
const [formData, setFormData] = useState({
plant: '',
scientificName: '',
age: '',
sex: '',
year: ''
});
const API_URL = 'http://localhost:5000/api';
useEffect(() => {
checkModelStatus();
}, []);
const checkModelStatus = async () => {
try {
const response = await fetch(`${API_URL}/model/info`);
const data = await response.json();
if (data.success) {
setModelInfo(data.info);
}
} catch (err) {
console.log('Model not yet trained');
}
};
const handleFileUpload = async (event) => {
const file = event.target.files[0];
if (!file) return;
setLoading(true);
setError(null);
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch(`${API_URL}/train`, {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success) {
setTrainingMetrics(data.metrics);
checkModelStatus();
alert('Model trained successfully!');
} else {
setError(data.error || 'Training failed');
}
} catch (err) {
setError('Error training model: ' + err.message);
} finally {
setLoading(false);
}
};
const handleInputChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value
});
};
const handlePredict = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
setPrediction(null);
// Convert form data to model input format
const inputData = createInputData(formData);
try {
const response = await fetch(`${API_URL}/predict`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(inputData)
});
const data = await response.json();
if (data.success) {
setPrediction(data.predictions);
} else {
setError(data.error || 'Prediction failed');
}
} catch (err) {
setError('Error making prediction: ' + err.message);
} finally {
setLoading(false);
}
};
const createInputData = (form) => {
// Initialize all features to 0
const input = {};
// Set plant name
const plantKey = `Plant_Name_${form.plant}`;
input[plantKey] = 1;
// Set scientific name
const sciKey = `Scientific_Name_${form.scientificName}`;
input[sciKey] = 1;
// Set sex counts (simplified)
input['Sex_Male_Count'] = form.sex === 'Male' ? 1 : 0;
input['Sex_Female_Count'] = form.sex === 'Female' ? 1 : 0;
// Set age range
if (form.age >= 18 && form.age <= 44) input['18-44_Years'] = 1;
else if (form.age >= 45 && form.age <= 64) input['45-64_Years'] = 1;
else if (form.age >= 65 && form.age <= 74) input['65-74_Years'] = 1;
else if (form.age >= 75) input['>=75_years'] = 1;
// Set year
if (form.year) input[form.year] = 1;
// Set geography
input['Geo_Asia'] = 1;
return input;
};
return (
<div className="App">
<header className="App-header">
<h1>🌿 Adverse Drug Reaction Prediction System</h1>
<p>Linear Regression Model for Herbal Medicine ADR Prediction</p>
</header>
<div className="container">
{/* Model Training Section */}
<section className="card">
<h2>📊 Model Training</h2>
<div className="upload-section">
<label htmlFor="file-upload" className="file-label">
{loading ? 'Training...' : 'Upload Training Dataset (CSV)'}
</label>
<input
id="file-upload"
type="file"
accept=".csv"
onChange={handleFileUpload}
disabled={loading}
/>
</div>
{trainingMetrics && (
<div className="metrics">
<h3>Training Metrics</h3>
<div className="metrics-grid">
<div className="metric">
<span className="metric-label">R² Score:</span>
<span className="metric-value">{trainingMetrics.r2_score.toFixed(4)}</span>
</div>
<div className="metric">
<span className="metric-label">RMSE:</span>
<span className="metric-value">{trainingMetrics.rmse.toFixed(4)}</span>
</div>
<div className="metric">
<span className="metric-label">MAE:</span>
<span className="metric-value">{trainingMetrics.mae.toFixed(4)}</span>
</div>
<div className="metric">
<span className="metric-label">Training Samples:</span>
<span className="metric-value">{trainingMetrics.training_samples}</span>
</div>
</div>
</div>
)}
{modelInfo && (
<div className="model-info">
<p>✅ Model Status: <strong>Trained</strong></p>
<p>Features: {modelInfo.n_features} | Targets: {modelInfo.n_targets}</p>
</div>
)}
</section>
{/* Prediction Section */}
<section className="card">
<h2>🔮 Make Prediction</h2>
<form onSubmit={handlePredict} className="prediction-form">
<div className="form-group">
<label>Plant Name:</label>
<select name="plant" value={formData.plant} onChange={handleInputChange} required>
<option value="">Select Plant</option>
<option value="Akapulko">Akapulko</option>
<option value="Ampalaya">Ampalaya</option>
<option value="Bawang">Bawang</option>
<option value="Bayabas">Bayabas</option>
<option value="Lagundi">Lagundi</option>
<option value="Sambong">Sambong</option>
</select>
</div>
<div className="form-group">
<label>Scientific Name:</label>
<select name="scientificName" value={formData.scientificName} onChange={handleInputChange} required>
<option value="">Select Scientific Name</option>
<option value="Allium sativum">Allium sativum</option>
<option value="Blumea balsamifera">Blumea balsamifera</option>
<option value="Momordica charantia">Momordica charantia</option>
<option value="Psidium guajava">Psidium guajava</option>
<option value="Senna alata">Senna alata</option>
<option value="Vitex negundo">Vitex negundo</option>
</select>
</div>
<div className="form-row">
<div className="form-group">
<label>Age:</label>
<input
type="number"
name="age"
value={formData.age}
onChange={handleInputChange}
min="1"
max="120"
required
/>
</div>
<div className="form-group">
<label>Sex:</label>
<select name="sex" value={formData.sex} onChange={handleInputChange} required>
<option value="">Select</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</div>
<div className="form-group">
<label>Year:</label>
<input
type="number"
name="year"
value={formData.year}
onChange={handleInputChange}
min="1980"
max="2025"
required
/>
</div>
</div>
<button type="submit" className="predict-btn" disabled={loading || !modelInfo}>
{loading ? 'Predicting...' : 'Predict ADR Risk'}
</button>
</form>
{error && (
<div className="error-message">
⚠️ {error}
</div>
)}
{prediction && (
<div className="results">
<h3>🎯 Prediction Results</h3>
<div className="result-section">
<h4>Top ADR Categories</h4>
<div className="predictions-list">
{prediction.top_adr_categories.map((item, idx) => (
<div key={idx} className="prediction-item">
<span className="prediction-rank">#{idx + 1}</span>
<span className="prediction-name">{item.name}</span>
<div className="prediction-bar">
<div
className="prediction-fill"
style={{ width: `${Math.max(0, Math.min(100, item.score * 100))}%` }}
></div>
</div>
<span className="prediction-score">{(item.score * 100).toFixed(2)}%</span>
</div>
))}
</div>
</div>
<div className="result-section">
<h4>Top ADR Subcategories</h4>
<div className="predictions-list">
{prediction.top_adr_subcategories.map((item, idx) => (
<div key={idx} className="prediction-item">
<span className="prediction-rank">#{idx + 1}</span>
<span className="prediction-name">{item.name}</span>
<div className="prediction-bar">
<div
className="prediction-fill"
style={{ width: `${Math.max(0, Math.min(100, item.score * 100))}%` }}
></div>
</div>
<span className="prediction-score">{(item.score * 100).toFixed(2)}%</span>
</div>
))}
</div>
</div>
</div>
)}
</section>
</div>
</div>
);
}
export default App;