Spaces:
No application file
No application file
flaskfiles
Browse files- Docker +20 -0
- app.py +22 -0
- index.html +77 -0
- model.py +94 -0
- requirements.txt +0 -0
- scripts.js +31 -0
- studentperformancefactor.csv +0 -0
- style.css +53 -0
Docker
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Use lightweight Python image
|
| 2 |
+
FROM python:3.10-slim
|
| 3 |
+
|
| 4 |
+
# Set working directory inside container
|
| 5 |
+
WORKDIR /app
|
| 6 |
+
|
| 7 |
+
# Copy requirements file
|
| 8 |
+
COPY requirements.txt .
|
| 9 |
+
|
| 10 |
+
# Install dependencies
|
| 11 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 12 |
+
|
| 13 |
+
# Copy project files
|
| 14 |
+
COPY . .
|
| 15 |
+
|
| 16 |
+
# Expose Flask port
|
| 17 |
+
EXPOSE 5000
|
| 18 |
+
|
| 19 |
+
# Run Flask application
|
| 20 |
+
CMD ["python", "app.py"]
|
app.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask, request, jsonify, send_from_directory
|
| 2 |
+
from flask_cors import CORS
|
| 3 |
+
from model import predict_exam_score
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
app = Flask(__name__, static_folder="../frontend")
|
| 7 |
+
CORS(app)
|
| 8 |
+
|
| 9 |
+
# Serve frontend
|
| 10 |
+
@app.route("/")
|
| 11 |
+
def serve_frontend():
|
| 12 |
+
return send_from_directory(app.static_folder, "index.html")
|
| 13 |
+
|
| 14 |
+
# Prediction API
|
| 15 |
+
@app.route("/predict", methods=["POST"])
|
| 16 |
+
def predict():
|
| 17 |
+
data = request.get_json()
|
| 18 |
+
prediction = predict_exam_score(data)
|
| 19 |
+
return jsonify({"predicted_score": round(prediction, 2)})
|
| 20 |
+
|
| 21 |
+
if __name__ == "__main__":
|
| 22 |
+
app.run(debug=True)
|
index.html
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<title>Student Performance Prediction</title>
|
| 5 |
+
<link rel="stylesheet" href="style.css">
|
| 6 |
+
</head>
|
| 7 |
+
<body>
|
| 8 |
+
|
| 9 |
+
<div class="container">
|
| 10 |
+
<h2>Student Performance Prediction</h2>
|
| 11 |
+
|
| 12 |
+
<label>Hours Studied:</label>
|
| 13 |
+
<input type="number" id="Hours_Studied">
|
| 14 |
+
|
| 15 |
+
<label>Attendance (%):</label>
|
| 16 |
+
<input type="number" id="Attendance">
|
| 17 |
+
|
| 18 |
+
<label>Previous Score:</label>
|
| 19 |
+
<input type="number" id="Previous_Scores">
|
| 20 |
+
|
| 21 |
+
<label>Sleep Hours:</label>
|
| 22 |
+
<input type="number" id="Sleep_Hours">
|
| 23 |
+
|
| 24 |
+
<label>Motivation Level (0–Low, 1–Medium, 2–High):</label>
|
| 25 |
+
<input type="number" id="Motivation_Level">
|
| 26 |
+
|
| 27 |
+
<label>Internet Access (0–No, 1–Yes):</label>
|
| 28 |
+
<input type="number" id="Internet_Access">
|
| 29 |
+
|
| 30 |
+
<label>Gender (0–Female, 1–Male):</label>
|
| 31 |
+
<input type="number" id="Gender">
|
| 32 |
+
|
| 33 |
+
<button onclick="predict()">Predict Exam Score</button>
|
| 34 |
+
|
| 35 |
+
<p id="result"></p>
|
| 36 |
+
</div>
|
| 37 |
+
|
| 38 |
+
<script>
|
| 39 |
+
function predict() {
|
| 40 |
+
document.getElementById("result").innerText = "Predicting...";
|
| 41 |
+
|
| 42 |
+
fetch("http://127.0.0.1:5000/predict", {
|
| 43 |
+
method: "POST",
|
| 44 |
+
headers: {
|
| 45 |
+
"Content-Type": "application/json"
|
| 46 |
+
},
|
| 47 |
+
body: JSON.stringify({
|
| 48 |
+
"Hours_Studied": Number(Hours_Studied.value),
|
| 49 |
+
"Attendance": Number(Attendance.value),
|
| 50 |
+
"Parental_Involvement": 2,
|
| 51 |
+
"Access_to_Resources": 2,
|
| 52 |
+
"Extracurricular_Activities": 1,
|
| 53 |
+
"Sleep_Hours": Number(Sleep_Hours.value),
|
| 54 |
+
"Previous_Scores": Number(Previous_Scores.value),
|
| 55 |
+
"Motivation_Level": Number(Motivation_Level.value),
|
| 56 |
+
"Internet_Access": Number(Internet_Access.value),
|
| 57 |
+
"Tutoring_Sessions": 1,
|
| 58 |
+
"Family_Income": 2,
|
| 59 |
+
"Teacher_Quality": 2,
|
| 60 |
+
"School_Type": 1,
|
| 61 |
+
"Peer_Influence": 1,
|
| 62 |
+
"Physical_Activity": 1,
|
| 63 |
+
"Learning_Disabilities": 0,
|
| 64 |
+
"Parental_Education_Level": 2,
|
| 65 |
+
"Distance_from_Home": 5,
|
| 66 |
+
"Gender": Number(Gender.value)
|
| 67 |
+
})
|
| 68 |
+
})
|
| 69 |
+
.then(res => res.json())
|
| 70 |
+
.then(data => {
|
| 71 |
+
result.innerText = "Predicted Exam Score: " + data.predicted_score;
|
| 72 |
+
});
|
| 73 |
+
}
|
| 74 |
+
</script>
|
| 75 |
+
|
| 76 |
+
</body>
|
| 77 |
+
</html>
|
model.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ===============================
|
| 2 |
+
# Student Performance Prediction
|
| 3 |
+
# ===============================
|
| 4 |
+
|
| 5 |
+
import pandas as pd
|
| 6 |
+
from sklearn.model_selection import train_test_split
|
| 7 |
+
from sklearn.preprocessing import LabelEncoder
|
| 8 |
+
from sklearn.ensemble import RandomForestRegressor
|
| 9 |
+
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
|
| 10 |
+
|
| 11 |
+
# -------------------------------
|
| 12 |
+
# 1. Load Dataset (USE YOUR PATH)
|
| 13 |
+
# -------------------------------
|
| 14 |
+
data = pd.read_csv(
|
| 15 |
+
r"C:\Users\tmeka\Downloads\StudentPerformanceFactors.csv"
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
print("Dataset loaded:", data.shape)
|
| 19 |
+
|
| 20 |
+
# -------------------------------
|
| 21 |
+
# 2. Encode Categorical Columns
|
| 22 |
+
# -------------------------------
|
| 23 |
+
for col in data.columns:
|
| 24 |
+
if data[col].dtype == "object":
|
| 25 |
+
data[col] = LabelEncoder().fit_transform(data[col])
|
| 26 |
+
|
| 27 |
+
# -------------------------------
|
| 28 |
+
# 3. Split Features & Target
|
| 29 |
+
# -------------------------------
|
| 30 |
+
X = data.drop("Exam_Score", axis=1) # 19 features
|
| 31 |
+
y = data["Exam_Score"]
|
| 32 |
+
|
| 33 |
+
print("Number of input features:", X.shape[1])
|
| 34 |
+
print("Feature names:\n", X.columns)
|
| 35 |
+
|
| 36 |
+
# -------------------------------
|
| 37 |
+
# 4. Train-Test Split
|
| 38 |
+
# -------------------------------
|
| 39 |
+
X_train, X_test, y_train, y_test = train_test_split(
|
| 40 |
+
X, y, test_size=0.2, random_state=42
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
# -------------------------------
|
| 44 |
+
# 5. Train Random Forest Model
|
| 45 |
+
# -------------------------------
|
| 46 |
+
model = RandomForestRegressor(
|
| 47 |
+
n_estimators=100,
|
| 48 |
+
random_state=42
|
| 49 |
+
)
|
| 50 |
+
model.fit(X_train, y_train)
|
| 51 |
+
|
| 52 |
+
print("Model trained successfully")
|
| 53 |
+
|
| 54 |
+
# -------------------------------
|
| 55 |
+
# 6. Evaluate Model
|
| 56 |
+
# -------------------------------
|
| 57 |
+
y_pred = model.predict(X_test)
|
| 58 |
+
|
| 59 |
+
print("\nModel Performance:")
|
| 60 |
+
print("MAE:", mean_absolute_error(y_test, y_pred))
|
| 61 |
+
print("MSE:", mean_squared_error(y_test, y_pred))
|
| 62 |
+
print("R2 :", r2_score(y_test, y_pred))
|
| 63 |
+
|
| 64 |
+
# -------------------------------
|
| 65 |
+
# 7. Predict for New Student
|
| 66 |
+
# -------------------------------
|
| 67 |
+
# MUST PROVIDE ALL 19 FEATURES
|
| 68 |
+
new_student = {
|
| 69 |
+
"Hours_Studied": 5,
|
| 70 |
+
"Attendance": 90,
|
| 71 |
+
"Parental_Involvement": 2,
|
| 72 |
+
"Access_to_Resources": 2,
|
| 73 |
+
"Extracurricular_Activities": 1,
|
| 74 |
+
"Sleep_Hours": 7,
|
| 75 |
+
"Previous_Scores": 85,
|
| 76 |
+
"Motivation_Level": 2,
|
| 77 |
+
"Internet_Access": 1,
|
| 78 |
+
"Tutoring_Sessions": 1,
|
| 79 |
+
"Family_Income": 2,
|
| 80 |
+
"Teacher_Quality": 2,
|
| 81 |
+
"School_Type": 1,
|
| 82 |
+
"Peer_Influence": 1,
|
| 83 |
+
"Physical_Activity": 1,
|
| 84 |
+
"Learning_Disabilities": 0,
|
| 85 |
+
"Parental_Education_Level": 2,
|
| 86 |
+
"Distance_from_Home": 5,
|
| 87 |
+
"Gender": 1
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
new_student_df = pd.DataFrame([new_student])
|
| 91 |
+
|
| 92 |
+
prediction = model.predict(new_student_df)
|
| 93 |
+
|
| 94 |
+
print("\nPredicted Exam Score:", round(prediction[0], 2))
|
requirements.txt
ADDED
|
File without changes
|
scripts.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
async function predictScore() {
|
| 2 |
+
|
| 3 |
+
const data = {
|
| 4 |
+
Hours_Studied: Number(document.getElementById("Hours_Studied").value),
|
| 5 |
+
Attendance: Number(document.getElementById("Attendance").value),
|
| 6 |
+
Previous_Scores: Number(document.getElementById("Previous_Scores").value),
|
| 7 |
+
Gender: Number(document.getElementById("Gender").value),
|
| 8 |
+
Parental_Education_Level: Number(document.getElementById("Parental_Education_Level").value),
|
| 9 |
+
Motivation_Level: Number(document.getElementById("Motivation_Level").value),
|
| 10 |
+
Internet_Access: Number(document.getElementById("Internet_Access").value),
|
| 11 |
+
School_Type: Number(document.getElementById("School_Type").value)
|
| 12 |
+
};
|
| 13 |
+
|
| 14 |
+
const response = await fetch("http://127.0.0.1:5000/predict", {
|
| 15 |
+
method: "POST",
|
| 16 |
+
headers: {
|
| 17 |
+
"Content-Type": "application/json"
|
| 18 |
+
},
|
| 19 |
+
body: JSON.stringify(data)
|
| 20 |
+
});
|
| 21 |
+
|
| 22 |
+
const result = await response.json();
|
| 23 |
+
|
| 24 |
+
if (result.predicted_score !== undefined) {
|
| 25 |
+
document.getElementById("result").innerText =
|
| 26 |
+
"Predicted Exam Score: " + result.predicted_score;
|
| 27 |
+
} else {
|
| 28 |
+
document.getElementById("result").innerText =
|
| 29 |
+
"Error: " + result.error;
|
| 30 |
+
}
|
| 31 |
+
}
|
studentperformancefactor.csv
ADDED
|
File without changes
|
style.css
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
body {
|
| 2 |
+
font-family: Arial, Helvetica, sans-serif;
|
| 3 |
+
background-color: #f4f6f8;
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
.container {
|
| 7 |
+
width: 360px;
|
| 8 |
+
margin: 60px auto;
|
| 9 |
+
background: #ffffff;
|
| 10 |
+
padding: 25px;
|
| 11 |
+
border-radius: 10px;
|
| 12 |
+
box-shadow: 0px 0px 12px rgba(0,0,0,0.15);
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
h2 {
|
| 16 |
+
text-align: center;
|
| 17 |
+
margin-bottom: 20px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
label {
|
| 21 |
+
font-size: 14px;
|
| 22 |
+
font-weight: bold;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
input {
|
| 26 |
+
width: 100%;
|
| 27 |
+
padding: 7px;
|
| 28 |
+
margin-top: 4px;
|
| 29 |
+
margin-bottom: 12px;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
button {
|
| 33 |
+
width: 100%;
|
| 34 |
+
padding: 10px;
|
| 35 |
+
background-color: #007bff;
|
| 36 |
+
color: white;
|
| 37 |
+
border: none;
|
| 38 |
+
font-size: 16px;
|
| 39 |
+
cursor: pointer;
|
| 40 |
+
border-radius: 5px;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
button:hover {
|
| 44 |
+
background-color: #0056b3;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
#result {
|
| 48 |
+
margin-top: 15px;
|
| 49 |
+
font-size: 18px;
|
| 50 |
+
color: green;
|
| 51 |
+
text-align: center;
|
| 52 |
+
font-weight: bold;
|
| 53 |
+
}
|