Skip to content

Commit 4f3cf4e

Browse files
authored
Create StudentMarks_Sentinel.py
1 parent a0c8ca4 commit 4f3cf4e

1 file changed

Lines changed: 246 additions & 0 deletions

File tree

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
"""
2+
StudentMarks Sentinel v1.0 - Academic Edition
3+
Smart Student Performance Prediction Tool
4+
ML-powered marks prediction with modern UI
5+
"""
6+
7+
import os, sys, threading
8+
import tkinter as tk
9+
from tkinter import filedialog, messagebox
10+
from tkinter import ttk
11+
12+
import pandas as pd
13+
import numpy as np
14+
15+
import ttkbootstrap as tb
16+
from ttkbootstrap.constants import *
17+
18+
from sklearn.linear_model import LinearRegression
19+
from sklearn.model_selection import train_test_split
20+
21+
22+
# ---------------------- UTIL ----------------------
23+
def resource_path(file_name):
24+
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
25+
return os.path.join(base_path, file_name)
26+
27+
28+
# ---------------------- ML WORKER ----------------------
29+
class MarksModelWorker:
30+
def __init__(self, csv_path, callbacks):
31+
self.csv_path = csv_path
32+
self.callbacks = callbacks
33+
self.model = LinearRegression()
34+
35+
def run(self):
36+
try:
37+
df = pd.read_csv(self.csv_path)
38+
39+
# Expected columns: StudyHours, Attendance, PreviousMarks, FinalMarks
40+
X = df[["StudyHours", "Attendance", "PreviousMarks"]]
41+
y = df["FinalMarks"]
42+
43+
X_train, X_test, y_train, y_test = train_test_split(
44+
X, y, test_size=0.2, random_state=42
45+
)
46+
47+
self.model.fit(X_train, y_train)
48+
score = self.model.score(X_test, y_test)
49+
50+
if "trained" in self.callbacks:
51+
self.callbacks["trained"](score, self.model)
52+
53+
except Exception as e:
54+
if "error" in self.callbacks:
55+
self.callbacks["error"](str(e))
56+
57+
58+
# ---------------------- MAIN APP ----------------------
59+
class StudentMarksApp:
60+
APP_NAME = "StudentMarks Sentinel"
61+
APP_VERSION = "1.0"
62+
63+
def __init__(self):
64+
self.root = tb.Window(themename="darkly")
65+
self.root.title(f"{self.APP_NAME} v{self.APP_VERSION}")
66+
self.root.minsize(1100, 650)
67+
68+
try:
69+
self.root.iconbitmap(resource_path("logo.ico"))
70+
except:
71+
pass
72+
73+
self.model = None
74+
self._build_ui()
75+
76+
# ---------------------- UI ----------------------
77+
def _build_ui(self):
78+
main = tb.Frame(self.root, padding=10)
79+
main.pack(fill=BOTH, expand=True)
80+
81+
tb.Label(
82+
main,
83+
text="🎓 StudentMarks Sentinel",
84+
font=("Segoe UI", 22, "bold")
85+
).pack(pady=(0, 4))
86+
87+
tb.Label(
88+
main,
89+
text="AI-Powered Student Marks Prediction",
90+
font=("Segoe UI", 10, "italic"),
91+
foreground="#9ca3af"
92+
).pack(pady=(0, 20))
93+
94+
# Dataset row
95+
row1 = tb.Frame(main)
96+
row1.pack(fill=X, pady=6)
97+
98+
self.dataset_entry = tb.Entry(row1, width=90)
99+
self.dataset_entry.pack(side=LEFT, fill=X, expand=True, padx=(0, 6))
100+
self.dataset_entry.insert(
101+
0,
102+
"Load CSV dataset (StudyHours, Attendance, PreviousMarks, FinalMarks)"
103+
)
104+
105+
tb.Button(
106+
row1,
107+
text="📂 Load Dataset",
108+
bootstyle=INFO,
109+
command=self.load_dataset
110+
).pack(side=LEFT, padx=3)
111+
112+
tb.Button(
113+
row1,
114+
text="🧠 Train Model",
115+
bootstyle=SUCCESS,
116+
command=self.train_model
117+
).pack(side=LEFT, padx=3)
118+
119+
# Stats
120+
self.stats_label = tb.Label(
121+
main,
122+
text="Model Status: Not trained",
123+
font=("Segoe UI", 10)
124+
)
125+
self.stats_label.pack(anchor=W, pady=(10, 10))
126+
127+
# Prediction inputs
128+
form = tb.Labelframe(main, text="Marks Prediction", padding=15)
129+
form.pack(fill=X, pady=10)
130+
131+
self.study_var = tk.DoubleVar()
132+
self.attendance_var = tk.DoubleVar()
133+
self.prev_marks_var = tk.DoubleVar()
134+
135+
tb.Label(form, text="Study Hours / Day").grid(row=0, column=0, padx=5, pady=5)
136+
tb.Entry(form, textvariable=self.study_var).grid(row=0, column=1, padx=5)
137+
138+
tb.Label(form, text="Attendance (%)").grid(row=0, column=2, padx=5)
139+
tb.Entry(form, textvariable=self.attendance_var).grid(row=0, column=3, padx=5)
140+
141+
tb.Label(form, text="Previous Marks").grid(row=0, column=4, padx=5)
142+
tb.Entry(form, textvariable=self.prev_marks_var).grid(row=0, column=5, padx=5)
143+
144+
tb.Button(
145+
form,
146+
text="📊 Predict Marks",
147+
bootstyle=PRIMARY,
148+
command=self.predict_marks
149+
).grid(row=0, column=6, padx=10)
150+
151+
tb.Button(
152+
form,
153+
text="ℹ️ About",
154+
bootstyle=INFO,
155+
command=self.show_about
156+
).grid(row=0, column=7, padx=10)
157+
158+
self.result_label = tb.Label(
159+
main,
160+
text="Predicted Final Marks: —",
161+
font=("Segoe UI", 16, "bold"),
162+
foreground="#4ade80"
163+
)
164+
self.result_label.pack(pady=20)
165+
166+
# ---------------------- Actions ----------------------
167+
def load_dataset(self):
168+
path = filedialog.askopenfilename(
169+
filetypes=[("CSV Files", "*.csv")]
170+
)
171+
if path:
172+
self.dataset_entry.delete(0, END)
173+
self.dataset_entry.insert(0, path)
174+
175+
def train_model(self):
176+
path = self.dataset_entry.get()
177+
if not os.path.isfile(path):
178+
messagebox.showerror("Error", "Invalid dataset path")
179+
return
180+
181+
self.stats_label.config(text="Training model...")
182+
183+
threading.Thread(
184+
target=self._train_worker,
185+
args=(path,),
186+
daemon=True
187+
).start()
188+
189+
def _train_worker(self, path):
190+
worker = MarksModelWorker(
191+
path,
192+
callbacks={
193+
"trained": self.on_trained,
194+
"error": self.on_error
195+
}
196+
)
197+
worker.run()
198+
199+
def on_trained(self, score, model):
200+
self.model = model
201+
self.stats_label.config(
202+
text=f"Model trained successfully | Accuracy: {score:.2f}"
203+
)
204+
205+
def on_error(self, msg):
206+
messagebox.showerror("Training Error", msg)
207+
self.stats_label.config(text="Training failed")
208+
209+
def predict_marks(self):
210+
if not self.model:
211+
messagebox.showwarning("Model", "Train the model first")
212+
return
213+
214+
X = pd.DataFrame([{
215+
"StudyHours": self.study_var.get(),
216+
"Attendance": self.attendance_var.get(),
217+
"PreviousMarks": self.prev_marks_var.get()
218+
}])
219+
220+
marks = self.model.predict(X)[0]
221+
222+
self.result_label.config(
223+
text=f"Predicted Final Marks: {marks:.2f}"
224+
)
225+
226+
# ---------------------- About ----------------------
227+
def show_about(self):
228+
messagebox.showinfo(
229+
f"About {self.APP_NAME}",
230+
f"{self.APP_NAME} v{self.APP_VERSION}\n\n"
231+
"• CSV-based ML training\n"
232+
"• Student performance prediction\n"
233+
"• Clean academic UI\n"
234+
"• Built with Python & Scikit-Learn\n\n"
235+
"🎓 Mate Technologies"
236+
)
237+
238+
# ---------------------- Run ----------------------
239+
def run(self):
240+
self.root.mainloop()
241+
242+
243+
# ---------------------- RUN ----------------------
244+
if __name__ == "__main__":
245+
app = StudentMarksApp()
246+
app.run()

0 commit comments

Comments
 (0)