kumneger49
update app.py to include the local path for the model and the metadata
672092c
import gradio as gr
import pickle
import json
import os
import pandas as pd
# Load model and preprocessing objects
MODEL_PATH = "model/nutrition_model.pkl"
METADATA_PATH = "model/nutrition_model_metadata.json"
PREPROCESS_PATH = "data/preprocessing_objects.pkl"
with open(MODEL_PATH, "rb") as f:
model = pickle.load(f)
with open(METADATA_PATH, "r") as f:
metadata = json.load(f)
with open(PREPROCESS_PATH, "rb") as f:
preprocessing_objects = pickle.load(f)
FEATURE_NAMES = metadata["feature_names"]
label_encoders = preprocessing_objects["label_encoders"]
scaler = preprocessing_objects["scaler"]
NUMERICALS = ["Ages", "Height", "Weight", "BMI", "Disease_Count"]
def preprocess_input(raw_instances):
# Convert to DataFrame
df = pd.DataFrame(raw_instances)
# --- Feature engineering: BMI ---
if "Height" in df.columns and "Weight" in df.columns:
df["BMI"] = df["Weight"] / ((df["Height"] / 100) ** 2)
# --- Disease flags ---
if "Disease" in df.columns:
diseases = ["Weight Gain", "Hypertension", "Heart Disease", "Kidney Disease", "Diabetes", "Acne"]
for disease in diseases:
df[f"Has_{disease.replace(' ', '_')}"] = df["Disease"].str.contains(disease, case=False, na=False).astype(int)
df["Disease_Count"] = df["Disease"].str.count(",") + 1
df["has_metabolic_disorder"] = df["Disease"].str.contains("diabetes|hypertension", case=False, na=False).astype(int)
df["has_cardiac_risk"] = df["Disease"].str.contains("heart disease", case=False, na=False).astype(int)
# --- Encode categoricals ---
for col in label_encoders:
if col in df.columns:
le = label_encoders[col]
# Ensure we pass a list of strings to the encoder, not a single string
# Print for debug
print(f"Encoding column {col}, values: {df[col].tolist()}")
df[f"{col}_encoded"] = le.transform(df[col].astype(str).tolist())
# --- Derived categoricals (use defaults if missing) ---
for col in ["Age_Group", "Weight_Category", "Disease_Severity", "activity_goal_combo"]:
if col not in df.columns:
if col in label_encoders:
df[col] = label_encoders[col].classes_[0] # Use the first valid class as default
else:
df[col] = "" # fallback
if col in label_encoders:
le = label_encoders[col]
df[f"{col}_encoded"] = le.transform(df[col].astype(str))
# --- Scale numericals ---
for col in NUMERICALS:
scaled_col = f"{col}_scaled"
if col in df.columns and scaler is not None and hasattr(scaler, "mean_"):
# Use scaler fitted on training data
try:
df[scaled_col] = scaler.transform(df[[col]]).flatten()
except Exception:
# If scaler expects more features, skip scaling for demo
pass
# --- Fill missing features with 0 or default ---
for feat in FEATURE_NAMES:
if feat not in df.columns:
df[feat] = 0
# --- Reorder columns ---
X = df[FEATURE_NAMES]
return X
def predict_nutrition(Age, Height, Weight, Gender, Activity_Level, Dietary_Preference, Disease):
print("Disease type:", type(Disease), "value:", Disease)
# Disease is a list from CheckboxGroup, but could be a string if only one selected
if isinstance(Disease, list):
if Disease:
disease_str = ", ".join(sorted(Disease))
else:
disease_str = ""
elif isinstance(Disease, str):
disease_str = Disease
else:
disease_str = ""
print("Disease string passed to DataFrame:", disease_str)
raw_instance = {
"Age": Age,
"Height": Height,
"Weight": Weight,
"Gender": Gender,
"Activity Level": Activity_Level,
"Dietary Preference": Dietary_Preference,
"Disease": disease_str
}
X = preprocess_input([raw_instance])
preds = model.predict(X)[0]
return float(preds[0]), float(preds[1]), float(preds[2])
# Disease options for user-friendly multi-select
DISEASE_OPTIONS = [
"Diabetes, Acne, Hypertension, Heart Disease",
"Diabetes, Acne, Hypertension, Kidney Disease",
"Diabetes, Acne, Weight Gain, Hypertension, Heart Disease",
"Diabetes, Acne, Weight Gain, Hypertension, Heart Disease, Kidney Disease",
"Diabetes, Acne, Weight Loss, Hypertension, Heart Disease, Kidney Disease",
"Hypertension, Heart Disease",
"Hypertension, Heart Disease, Kidney Disease",
"Hypertension, Kidney Disease",
"Kidney Disease",
"Weight Gain",
"Weight Gain, Hypertension, Heart Disease",
"Weight Gain, Hypertension, Heart Disease, Kidney Disease",
"Weight Gain, Kidney Disease"
]
# Define Gradio interface
demo = gr.Interface(
fn=predict_nutrition,
inputs=[
gr.Number(label="Age"),
gr.Number(label="Height (cm)"),
gr.Number(label="Weight (kg)"),
gr.Dropdown(choices=["Male", "Female"], label="Gender", value="Male"),
gr.Dropdown(
choices=[
"Extremely Active", "Lightly Active", "Moderately Active", "Sedentary", "Very Active"
],
label="Activity Level",
value="Sedentary"
),
gr.Dropdown(choices=["Omnivore", "Vegetarian", "Vegan"], label="Dietary Preference", value="Omnivore"),
gr.Dropdown(choices=DISEASE_OPTIONS, label="Disease", value=DISEASE_OPTIONS[0])
],
outputs=[
gr.Number(label="Protein"),
gr.Number(label="Sodium"),
gr.Number(label="Calories")
],
title="Personalized Nutrition Predictor",
description="Enter your details to get personalized nutrition recommendations."
)
if __name__ == "__main__":
demo.launch(share=True)