Skip to content

Commit ce110f7

Browse files
authored
Create Diabetes_Predictor.py
1 parent 0b939e8 commit ce110f7

1 file changed

Lines changed: 313 additions & 0 deletions

File tree

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
"""
2+
Diabetes Predictor v2.0 - Professional Edition
3+
AI-Powered Diabetes Risk Prediction System
4+
Supports single entries & CSV batch predictions with polished GUI
5+
"""
6+
7+
import os, sys, threading
8+
import pandas as pd
9+
from sklearn.model_selection import train_test_split
10+
from sklearn.ensemble import RandomForestClassifier
11+
import tkinter as tk
12+
from tkinter import filedialog, messagebox, ttk
13+
14+
import ttkbootstrap as tb
15+
from ttkbootstrap.constants import *
16+
17+
try:
18+
from tkinterdnd2 import TkinterDnD, DND_FILES
19+
DND_ENABLED = True
20+
except ImportError:
21+
DND_ENABLED = False
22+
print("Drag & Drop requires tkinterdnd2: pip install tkinterdnd2")
23+
24+
25+
# ---------------------- UTIL ----------------------
26+
def resource_path(file_name):
27+
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
28+
return os.path.join(base_path, file_name)
29+
30+
31+
# ---------------------- PREDICTION WORKER ----------------------
32+
class PredictionWorker:
33+
def __init__(self, data_files, callbacks):
34+
self.data_files = data_files
35+
self.callbacks = callbacks
36+
self._running = True
37+
self.model = None
38+
self._train_model()
39+
40+
def _train_model(self):
41+
try:
42+
df = pd.read_csv("diabetes.csv")
43+
X = df.drop("Outcome", axis=1)
44+
y = df["Outcome"]
45+
self.model = RandomForestClassifier(n_estimators=100, random_state=42)
46+
self.model.fit(X, y)
47+
except Exception as e:
48+
print(f"Training error: {e}")
49+
self.model = None
50+
51+
def stop(self):
52+
self._running = False
53+
54+
def run(self):
55+
results = []
56+
total_files = len(self.data_files)
57+
for i, path in enumerate(self.data_files):
58+
if not self._running:
59+
break
60+
try:
61+
df = pd.read_csv(path)
62+
if self.model is not None:
63+
pred = self.model.predict(df)
64+
for j, p in enumerate(pred):
65+
results.append((path, j + 1, p))
66+
if "found" in self.callbacks:
67+
self.callbacks["found"](path, j + 1, p)
68+
except Exception as e:
69+
results.append((path, 0, f"Error: {e}"))
70+
if "progress" in self.callbacks:
71+
self.callbacks["progress"](int((i + 1) / total_files * 100))
72+
if "finished" in self.callbacks:
73+
self.callbacks["finished"]()
74+
75+
76+
# ---------------------- MAIN APP ----------------------
77+
class DiabetesPredictorApp:
78+
APP_NAME = "Diabetes Predictor"
79+
APP_VERSION = "2.0"
80+
81+
def __init__(self):
82+
if DND_ENABLED:
83+
self.root = TkinterDnD.Tk()
84+
else:
85+
self.root = tb.Window(themename="darkly")
86+
self.root.title(f"{self.APP_NAME} v{self.APP_VERSION}")
87+
self.root.minsize(1000, 700)
88+
89+
self.worker_obj = None
90+
self.file_set = set()
91+
self.smooth_value = 0
92+
self.target_progress = 0
93+
94+
self._build_ui()
95+
self._apply_styles()
96+
97+
# ---------------------- UI ----------------------
98+
def _build_ui(self):
99+
main = tb.Frame(self.root, padding=10)
100+
main.pack(fill=tk.BOTH, expand=True)
101+
102+
tb.Label(main, text=f"🩺 {self.APP_NAME}", font=("Segoe UI", 22, "bold")).pack(pady=(0,4))
103+
tb.Label(main, text="AI-Powered Diabetes Risk Prediction", font=("Segoe UI", 10, "italic"), foreground="#9ca3af").pack(pady=(0,20))
104+
105+
# ------------------ Tabs ------------------
106+
self.tabs = tb.Notebook(main)
107+
self.tabs.pack(fill=tk.BOTH, expand=True)
108+
109+
# Batch Prediction Tab
110+
self.batch_tab = tb.Frame(self.tabs)
111+
self.tabs.add(self.batch_tab, text="📂 Batch CSV Prediction")
112+
113+
self._build_batch_tab()
114+
115+
# Single Entry Prediction Tab
116+
self.single_tab = tb.Frame(self.tabs)
117+
self.tabs.add(self.single_tab, text="📝 Single Entry Prediction")
118+
119+
self._build_single_tab()
120+
121+
# ---------------------- Batch Tab ----------------------
122+
def _build_batch_tab(self):
123+
row1 = tb.Frame(self.batch_tab)
124+
row1.pack(fill=tk.X, pady=(0,6))
125+
126+
self.path_input = tb.Entry(row1, width=70)
127+
self.path_input.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0,6))
128+
self.path_input.insert(0, "Drag & drop CSV files here…")
129+
130+
browse_btn = tb.Button(row1, text="📂 Browse", bootstyle=INFO, command=self.browse)
131+
browse_btn.pack(side=tk.LEFT, padx=3)
132+
133+
self.start_btn = tb.Button(row1, text="🚀 Predict", bootstyle=SUCCESS, command=self.start)
134+
self.start_btn.pack(side=tk.LEFT, padx=3)
135+
136+
self.cancel_btn = tb.Button(row1, text="⏹ Cancel", bootstyle=DANGER, command=self.cancel)
137+
self.cancel_btn.pack(side=tk.LEFT, padx=3)
138+
self.cancel_btn.config(state=DISABLED)
139+
140+
export_btn = tb.Button(row1, text="💾 Export Results", bootstyle=PRIMARY, command=self.export_results)
141+
export_btn.pack(side=tk.LEFT, padx=3)
142+
143+
# Progress
144+
self.progress = tb.Progressbar(self.batch_tab, bootstyle="success-striped", maximum=100)
145+
self.progress.pack(fill=tk.X, pady=(0,6))
146+
147+
# Treeview for results
148+
columns = ("selected", "file", "entry", "prediction")
149+
self.tree = ttk.Treeview(self.batch_tab, columns=columns, show="headings", selectmode="extended", height=20)
150+
self.tree.heading("selected", text="✅")
151+
self.tree.heading("file", text="File")
152+
self.tree.heading("entry", text="Entry #")
153+
self.tree.heading("prediction", text="Predicted Outcome")
154+
self.tree.column("selected", width=50, anchor=tk.CENTER)
155+
self.tree.column("file", width=350)
156+
self.tree.column("entry", width=80, anchor=tk.CENTER)
157+
self.tree.column("prediction", width=150, anchor=tk.CENTER)
158+
self.tree.pack(fill=tk.BOTH, expand=True, pady=(0,6))
159+
160+
if DND_ENABLED:
161+
self.tree.drop_target_register(DND_FILES)
162+
self.tree.dnd_bind("<<Drop>>", self.on_drop)
163+
164+
self.root.after(15, self.animate_progress)
165+
166+
# ---------------------- Single Entry Tab ----------------------
167+
def _build_single_tab(self):
168+
tb.Label(self.single_tab, text="Enter Patient Data:", font=("Segoe UI", 14, "bold")).pack(pady=(0,10))
169+
170+
form_frame = tb.Frame(self.single_tab)
171+
form_frame.pack(pady=10)
172+
173+
# Features used in Pima dataset
174+
self.single_inputs = {}
175+
features = ["Pregnancies","Glucose","BloodPressure","SkinThickness","Insulin","BMI","DiabetesPedigreeFunction","Age"]
176+
for i, feature in enumerate(features):
177+
row = tb.Frame(form_frame)
178+
row.pack(fill=tk.X, pady=2)
179+
tb.Label(row, text=f"{feature}:", width=25, anchor="w").pack(side=tk.LEFT)
180+
entry = tb.Entry(row, width=20)
181+
entry.pack(side=tk.LEFT)
182+
self.single_inputs[feature] = entry
183+
184+
tb.Button(self.single_tab, text="🩺 Predict Single Entry", bootstyle=SUCCESS, command=self.predict_single).pack(pady=10)
185+
self.single_result = tb.Label(self.single_tab, text="", font=("Segoe UI", 12, "bold"))
186+
self.single_result.pack(pady=10)
187+
188+
# ---------------------- File Handling ----------------------
189+
def browse(self):
190+
files = filedialog.askopenfilenames(filetypes=[("CSV Files","*.csv")])
191+
if files:
192+
self._queue_files(files)
193+
194+
def on_drop(self, event):
195+
dropped_paths = self.root.tk.splitlist(event.data)
196+
self._queue_files(dropped_paths)
197+
198+
def _queue_files(self, files):
199+
for f in files:
200+
if f not in self.file_set:
201+
self.file_set.add(f)
202+
self.tree.insert("", tk.END, values=("☑️", f, "-", "-"))
203+
204+
# ---------------------- Actions ----------------------
205+
def start(self):
206+
selected_files = [self.tree.item(i)['values'][1] for i in self.tree.get_children()
207+
if self.tree.item(i)['values'][0]=="☑️"]
208+
if not selected_files:
209+
messagebox.showwarning("No Selection", "Select CSV files before predicting.")
210+
return
211+
self.progress["value"] = 0
212+
self.smooth_value = 0
213+
self.target_progress = 0
214+
self.start_btn.config(state=DISABLED)
215+
self.cancel_btn.config(state=NORMAL)
216+
threading.Thread(target=self._run_worker, args=(selected_files,), daemon=True).start()
217+
218+
def _run_worker(self, files):
219+
self.worker_obj = PredictionWorker(
220+
files,
221+
callbacks={
222+
"found": self.add_prediction,
223+
"progress": self.set_target,
224+
"finished": self.finish
225+
}
226+
)
227+
self.worker_obj.run()
228+
229+
def add_prediction(self, file, entry, prediction):
230+
for i in self.tree.get_children():
231+
if self.tree.item(i)['values'][1] == file and self.tree.item(i)['values'][2] == "-":
232+
self.tree.item(i, values=("☑️", file, entry, prediction))
233+
break
234+
235+
def set_target(self, v):
236+
self.target_progress = v
237+
238+
def animate_progress(self):
239+
if self.smooth_value < self.target_progress:
240+
self.smooth_value += 1
241+
self.progress["value"] = self.smooth_value
242+
self.root.after(15, self.animate_progress)
243+
244+
def cancel(self):
245+
if self.worker_obj:
246+
self.worker_obj.stop()
247+
self.finish()
248+
249+
def finish(self):
250+
self.start_btn.config(state=NORMAL)
251+
self.cancel_btn.config(state=DISABLED)
252+
self.progress["value"] = 100
253+
254+
# ---------------------- Single Entry Prediction ----------------------
255+
def predict_single(self):
256+
try:
257+
values = [float(self.single_inputs[f].get()) for f in self.single_inputs]
258+
except ValueError:
259+
messagebox.showerror("Invalid Input", "Please enter valid numeric values for all fields.")
260+
return
261+
262+
try:
263+
df = pd.read_csv("diabetes.csv")
264+
X = df.drop("Outcome", axis=1)
265+
y = df["Outcome"]
266+
model = RandomForestClassifier(n_estimators=100, random_state=42)
267+
model.fit(X, y)
268+
pred = model.predict([values])[0]
269+
self.single_result.config(text=f"Predicted Outcome: {'Diabetic' if pred==1 else 'Non-Diabetic'}", foreground="#4ade80" if pred==0 else "#f87171")
270+
except Exception as e:
271+
messagebox.showerror("Prediction Error", str(e))
272+
273+
# ---------------------- Export ----------------------
274+
def export_results(self):
275+
selected = [self.tree.item(i)['values'] for i in self.tree.get_children() if self.tree.item(i)['values'][0]=="☑️"]
276+
if not selected:
277+
messagebox.showwarning("Export", "No results to export.")
278+
return
279+
path = filedialog.asksaveasfilename(defaultextension=".csv", filetypes=[("CSV Files","*.csv")])
280+
if path:
281+
import csv
282+
with open(path, "w", newline="") as f:
283+
writer = csv.writer(f)
284+
writer.writerow(["File","Entry #","Predicted Outcome"])
285+
for row in selected:
286+
writer.writerow(row[1:])
287+
messagebox.showinfo("Export", "Results exported successfully!")
288+
289+
# ---------------------- About ----------------------
290+
def show_about(self):
291+
messagebox.showinfo(f"About {self.APP_NAME}",
292+
f"{self.APP_NAME} v{self.APP_VERSION}\n\n"
293+
"• Batch prediction of diabetes risk from CSV files\n"
294+
"• Single patient entry prediction\n"
295+
"• Drag & drop files or browse\n"
296+
"• Real-time updates for batch predictions\n"
297+
"• Export results to CSV\n\n"
298+
"🏢 Built professionally with Tkinter & AI")
299+
300+
# ---------------------- Styles ----------------------
301+
def _apply_styles(self):
302+
self.root.style = tb.Style(theme="darkly")
303+
self.root.style.configure("TProgressbar", troughcolor="#1b1f3a", background="#7c3aed", thickness=14)
304+
305+
# ---------------------- Run ----------------------
306+
def run(self):
307+
self.root.mainloop()
308+
309+
310+
# ---------------------- RUN ----------------------
311+
if __name__ == "__main__":
312+
app = DiabetesPredictorApp()
313+
app.run()

0 commit comments

Comments
 (0)