Spaces:
Runtime error
Runtime error
Upload folder using huggingface_hub
Browse files- backend/main.py +30 -6
- frontend/pages/5_MLOps_Settings.py +18 -2
backend/main.py
CHANGED
|
@@ -489,17 +489,41 @@ async def retrain(file: UploadFile = File(...)):
|
|
| 489 |
data_path = '/app/data/patient_dataset.csv' if os.path.exists('/app/data') else '../data/patient_dataset.csv' if os.path.exists('../data') else 'data/patient_dataset.csv'
|
| 490 |
os.makedirs(os.path.dirname(data_path), exist_ok=True)
|
| 491 |
|
| 492 |
-
content = await file.read()
|
| 493 |
-
with open(data_path, "wb") as f:
|
| 494 |
-
f.write(content)
|
| 495 |
-
|
| 496 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
from models import train_models
|
| 498 |
await asyncio.to_thread(train_models)
|
| 499 |
|
| 500 |
global ensemble_system
|
| 501 |
ensemble_system = None
|
| 502 |
|
| 503 |
-
return {"status": "success", "message": "
|
| 504 |
except Exception as e:
|
| 505 |
-
return {"error": str(e)}
|
|
|
|
| 489 |
data_path = '/app/data/patient_dataset.csv' if os.path.exists('/app/data') else '../data/patient_dataset.csv' if os.path.exists('../data') else 'data/patient_dataset.csv'
|
| 490 |
os.makedirs(os.path.dirname(data_path), exist_ok=True)
|
| 491 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 492 |
try:
|
| 493 |
+
content = await file.read()
|
| 494 |
+
import io
|
| 495 |
+
new_df = pd.read_csv(io.BytesIO(content))
|
| 496 |
+
new_df.columns = [c.strip() for c in new_df.columns]
|
| 497 |
+
|
| 498 |
+
if os.path.exists(data_path):
|
| 499 |
+
existing_df = pd.read_csv(data_path)
|
| 500 |
+
existing_df.columns = [c.strip() for c in existing_df.columns]
|
| 501 |
+
|
| 502 |
+
# Validate schema
|
| 503 |
+
required_cols = set(existing_df.columns)
|
| 504 |
+
provided_cols = set(new_df.columns)
|
| 505 |
+
|
| 506 |
+
if not required_cols.issubset(provided_cols):
|
| 507 |
+
missing = required_cols - provided_cols
|
| 508 |
+
return {"error": f"Schema mismatch. Missing columns: {list(missing)}"}
|
| 509 |
+
|
| 510 |
+
# Ensure columns are in the same order and select only necessary ones
|
| 511 |
+
new_df = new_df[existing_df.columns]
|
| 512 |
+
|
| 513 |
+
# Append data
|
| 514 |
+
combined_df = pd.concat([existing_df, new_df], ignore_index=True)
|
| 515 |
+
else:
|
| 516 |
+
combined_df = new_df
|
| 517 |
+
|
| 518 |
+
# Save validated and combined dataset
|
| 519 |
+
combined_df.to_csv(data_path, index=False, encoding='utf-8')
|
| 520 |
+
|
| 521 |
from models import train_models
|
| 522 |
await asyncio.to_thread(train_models)
|
| 523 |
|
| 524 |
global ensemble_system
|
| 525 |
ensemble_system = None
|
| 526 |
|
| 527 |
+
return {"status": "success", "message": f"Dataset updated (now {len(combined_df)} records) and ensemble retrained successfully!"}
|
| 528 |
except Exception as e:
|
| 529 |
+
return {"error": f"Retraining failed: {str(e)}"}
|
frontend/pages/5_MLOps_Settings.py
CHANGED
|
@@ -8,9 +8,25 @@ if "hf.space" in os.getenv("SPACE_ID", ""):
|
|
| 8 |
API_URL = "http://localhost:8000"
|
| 9 |
|
| 10 |
st.title("🔄 MLOps & Retraining")
|
| 11 |
-
st.markdown("Dynamically update the TinyML ensemble models by providing a new dataset.")
|
| 12 |
|
| 13 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
uploaded_file = st.file_uploader("Upload New Patient Dataset (CSV)", type="csv")
|
| 16 |
|
|
|
|
| 8 |
API_URL = "http://localhost:8000"
|
| 9 |
|
| 10 |
st.title("🔄 MLOps & Retraining")
|
| 11 |
+
st.markdown("Dynamically update the TinyML ensemble models by providing a new dataset. The system uses an **append-only** strategy to maintain data integrity.")
|
| 12 |
|
| 13 |
+
with st.expander("📊 Data Submission Guide (Required Schema)", expanded=True):
|
| 14 |
+
st.markdown("""
|
| 15 |
+
To ensure the retraining pipeline succeeds, your CSV **must** include the following columns (case-sensitive):
|
| 16 |
+
|
| 17 |
+
1. **Patient Number**: Unique identifier for the patient.
|
| 18 |
+
2. **Heart Rate (bpm)**: Numeric value.
|
| 19 |
+
3. **SpO2 Level (%)**: Numeric value.
|
| 20 |
+
4. **Systolic Blood Pressure (mmHg)**: Numeric value.
|
| 21 |
+
5. **Diastolic Blood Pressure (mmHg)**: Numeric value.
|
| 22 |
+
6. **Body Temperature (°C)**: Numeric value.
|
| 23 |
+
7. **Fall Detection**: 'Yes' or 'No'.
|
| 24 |
+
8. **Predicted Disease**: The target label (e.g., Healthy, Heart Disease).
|
| 25 |
+
|
| 26 |
+
*Note: If you submit a file with a different schema, the system will reject the update to prevent dashboard crashes.*
|
| 27 |
+
""")
|
| 28 |
+
|
| 29 |
+
st.info("💡 **Safety Logic:** New data will be validated and appended to the existing dataset. The original records are always preserved.")
|
| 30 |
|
| 31 |
uploaded_file = st.file_uploader("Upload New Patient Dataset (CSV)", type="csv")
|
| 32 |
|