ntam0001's picture
Update app.py
5529e78 verified
raw
history blame
10.5 kB
import gradio as gr
import pandas as pd
import numpy as np
import pickle
import json
import tensorflow as tf
from tensorflow.keras.models import model_from_json
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import os
# Set environment variable to avoid oneDNN warnings
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
# Initialize model components at startup
def load_model_artifacts():
try:
# Load model architecture
with open('model_architecture.json', 'r') as json_file:
model_json = json_file.read()
model = model_from_json(model_json)
# Load model weights
model.load_weights('final_model.h5')
# Load scaler
with open('scaler.pkl', 'rb') as f:
scaler = pickle.load(f)
# Load metadata
with open('metadata.json', 'r') as f:
metadata = json.load(f)
return model, scaler, metadata
except Exception as e:
print(f"❌ Error loading model artifacts: {str(e)}")
return None, None, {}
# Load model
model, scaler, metadata = load_model_artifacts()
if model:
feature_names = metadata.get('feature_names', ['Feature_1', 'Feature_2'])
print(f"βœ… Model loaded successfully with features: {feature_names}")
else:
feature_names = ['Feature_1', 'Feature_2']
print("❌ Model failed to load - running in demo mode with placeholder features")
def predict_student_eligibility(*args):
try:
if model is None or scaler is None:
raise RuntimeError("Model not loaded - please check the model files")
# Create input dictionary
input_data = {feature_names[i]: float(args[i]) for i in range(len(feature_names))}
# Create DataFrame ensuring correct column order
input_df = pd.DataFrame([input_data], columns=feature_names)
# Scale features
input_scaled = scaler.transform(input_df)
# Reshape for CNN (samples, timesteps, features)
input_reshaped = input_scaled.reshape(input_scaled.shape[0], input_scaled.shape[1], 1)
# Make prediction
probability = float(model.predict(input_reshaped)[0][0])
prediction = "Eligible" if probability > 0.5 else "Not Eligible"
confidence = abs(probability - 0.5) * 2 # Convert to 0-1 range
# Create visualization
fig = create_prediction_viz(probability, prediction, input_data)
return prediction, f"{probability:.4f}", f"{confidence:.4f}", fig
except Exception as e:
error_msg = f"Error: {str(e)}"
print(error_msg)
return error_msg, "N/A", "N/A", create_error_plot(error_msg)
def create_error_plot(message="Model not available or error occurred"):
fig = go.Figure()
fig.add_annotation(
text=message,
xref="paper", yref="paper",
x=0.5, y=0.5, xanchor='center', yanchor='middle',
showarrow=False, font=dict(size=16, color="red")
)
fig.update_layout(
xaxis={'visible': False},
yaxis={'visible': False},
height=400,
margin=dict(l=20, r=20, t=30, b=20)
)
return fig
def create_prediction_viz(probability, prediction, input_data):
try:
fig = make_subplots(
rows=2, cols=2,
subplot_titles=('Prediction Probability', 'Confidence Meter', 'Input Features', 'Probability Distribution'),
specs=[[{"type": "indicator"}, {"type": "indicator"}],
[{"type": "bar"}, {"type": "scatter"}]]
)
# Prediction probability gauge
fig.add_trace(
go.Indicator(
mode="gauge+number",
value=probability,
title={'text': "Eligibility Probability"},
gauge={
'axis': {'range': [None, 1]},
'bar': {'color': "darkblue"},
'steps': [
{'range': [0, 0.5], 'color': "lightcoral"},
{'range': [0.5, 1], 'color': "lightgreen"}
],
'threshold': {
'line': {'color': "red", 'width': 4},
'thickness': 0.75,
'value': 0.5
}
}
), row=1, col=1
)
# Confidence meter
confidence = abs(probability - 0.5) * 2
fig.add_trace(
go.Indicator(
mode="gauge+number",
value=confidence,
title={'text': "Prediction Confidence"},
gauge={
'axis': {'range': [None, 1]},
'bar': {'color': "orange"},
'steps': [
{'range': [0, 0.3], 'color': "lightcoral"},
{'range': [0.3, 0.7], 'color': "lightyellow"},
{'range': [0.7, 1], 'color': "lightgreen"}
]
}
), row=1, col=2
)
# Input features bar chart
features = list(input_data.keys())
values = list(input_data.values())
fig.add_trace(
go.Bar(
x=features,
y=values,
name="Input Values",
marker_color="skyblue",
text=values,
textposition='auto'
),
row=2, col=1
)
# Probability distribution
fig.add_trace(
go.Scatter(
x=[0, 1],
y=[probability, probability],
mode='lines+markers',
name="Probability",
line=dict(color="red", width=3),
marker=dict(size=10)
),
row=2, col=2
)
fig.update_layout(
height=800,
showlegend=False,
title_text="Student Eligibility Prediction Dashboard",
title_x=0.5,
margin=dict(l=50, r=50, t=100, b=50)
)
# Update x-axis for probability plot
fig.update_xaxes(title_text="", row=2, col=2, range=[-0.1, 1.1])
fig.update_yaxes(title_text="Probability", row=2, col=2, range=[0, 1])
return fig
except Exception as e:
return create_error_plot(str(e))
def batch_predict(file):
try:
if model is None or scaler is None:
return "Model not loaded. Please check if all model files are uploaded.", None
if file is None:
return "Please upload a CSV file.", None
df = pd.read_csv(file)
# Check for required features
missing_features = set(feature_names) - set(df.columns)
if missing_features:
return f"Missing features: {', '.join(missing_features)}", None
# Ensure correct column order
df_features = df[feature_names]
df_scaled = scaler.transform(df_features)
df_reshaped = df_scaled.reshape(df_scaled.shape[0], df_scaled.shape[1], 1)
probabilities = model.predict(df_reshaped).flatten()
predictions = ["Eligible" if p > 0.5 else "Not Eligible" for p in probabilities]
results_df = df.copy()
results_df['Probability'] = probabilities
results_df['Prediction'] = predictions
results_df['Confidence'] = np.abs(probabilities - 0.5) * 2
output_file = "batch_predictions.csv"
results_df.to_csv(output_file, index=False)
eligible_count = predictions.count('Eligible')
not_eligible_count = predictions.count('Not Eligible')
summary = f"""Batch Prediction Summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
πŸ“Š Total predictions: {len(results_df)}
βœ… Eligible: {eligible_count} ({eligible_count / len(predictions) * 100:.1f}%)
❌ Not Eligible: {not_eligible_count} ({not_eligible_count / len(predictions) * 100:.1f}%)
πŸ“ˆ Average Probability: {np.mean(probabilities):.4f}
🎯 Average Confidence: {np.mean(np.abs(probabilities - 0.5) * 2):.4f}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Results saved to: {output_file}
"""
return summary, output_file
except Exception as e:
return f"Error processing file: {str(e)}", None
# Gradio UI
with gr.Blocks(theme=gr.themes.Soft(), title="Student Eligibility Predictor") as demo:
gr.Markdown("# πŸŽ“ Student Eligibility Prediction")
gr.Markdown("This app predicts student eligibility based on academic performance metrics.")
with gr.Tabs():
with gr.Tab("πŸ“ Single Prediction"):
with gr.Row():
with gr.Column():
inputs = [gr.Number(label=feature, value=75) for feature in feature_names]
predict_btn = gr.Button("Predict", variant="primary")
with gr.Column():
prediction = gr.Textbox(label="Prediction")
probability = gr.Textbox(label="Probability")
confidence = gr.Textbox(label="Confidence")
plot = gr.Plot()
predict_btn.click(
predict_student_eligibility,
inputs=inputs,
outputs=[prediction, probability, confidence, plot]
)
with gr.Tab("πŸ“ Batch Prediction"):
gr.Markdown("Upload a CSV file with student data to get batch predictions.")
with gr.Row():
with gr.Column():
file_input = gr.File(
label="Upload CSV",
file_types=[".csv"],
type="filepath"
)
batch_btn = gr.Button("Process Batch", variant="primary")
with gr.Column():
batch_output = gr.Textbox(label="Results", lines=10)
download = gr.File(label="Download Predictions")
batch_btn.click(
batch_predict,
inputs=file_input,
outputs=[batch_output, download]
)
# Footer
gr.Markdown("---")
gr.Markdown("> Note: This model was trained on student eligibility data. Ensure your input features match the training data format.")
# Launch app
if __name__ == "__main__":
demo.launch()