Spaces:
Configuration error
Configuration error
| 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; |