namngo commited on
Commit
f98cbdb
·
verified ·
1 Parent(s): a226846

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +117 -227
app.py CHANGED
@@ -1,10 +1,6 @@
1
  import streamlit as st
2
  import numpy as np
3
  import joblib
4
- import gspread
5
- from oauth2client.service_account import ServiceAccountCredentials
6
- from datetime import datetime
7
- import json
8
 
9
  # ===== Load models =====
10
  model_full = joblib.load("random_forest_model_full.pkl")
@@ -20,7 +16,7 @@ st.markdown("""
20
  font-family: 'Poppins', sans-serif;
21
  }
22
  .block-container {
23
- padding: 2rem 2rem 2rem 2rem;
24
  }
25
  .stButton button {
26
  background: linear-gradient(90deg, #4F8BF9 0%, #8E2DE2 100%);
@@ -34,282 +30,176 @@ st.markdown("""
34
  </style>
35
  """, unsafe_allow_html=True)
36
 
37
- # ===== GSheet integration =====
38
- @st.cache_resource
39
- def get_gsheet_client():
40
- scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
41
- creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
42
- client = gspread.authorize(creds)
43
- return client
44
-
45
- # ===== Save to Google Sheets =====
46
- def save_to_gsheet(name, student_id, major, prediction, semester_data, sheet_name="Trang tính1"):
47
- # Get the current date and time
48
- now = datetime.now()
49
- current_time = now.strftime("%Y-%m-%d %H:%M:%S")
50
-
51
- # Ensure prediction is in the expected format (0 or 1)
52
- if isinstance(prediction, np.ndarray):
53
- prediction = int(prediction[0]) # Convert to int if it's ndarray
54
-
55
- elif isinstance(prediction, np.int64):
56
- prediction = int(prediction) # Convert np.int64 to int
57
-
58
- # Flatten semester data to individual columns for each semester
59
- semester_data_flat = [str(val) for val in semester_data] # Convert all semester data values to strings
60
-
61
- # Create a data row to insert into the sheet
62
- data_row = [name, student_id, major, prediction, current_time] + semester_data_flat
63
-
64
- # Connect to Google Sheets
65
- client = get_gsheet_client()
66
-
67
- # Use the Spreadsheet ID (replace with your actual ID)
68
- sheet_id = "1i7bDNvLVLXN93_e-FN0JLzpg1jb64Z_aEuyPjIfwbdQ" # Use your actual ID here
69
- sheet = client.open_by_key(sheet_id).worksheet(sheet_name)
70
-
71
- # Get all values from the sheet to check if the first row is empty (i.e., headers not created yet)
72
- all_values = sheet.get_all_values()
73
-
74
- # If the sheet is empty or if headers are missing, insert headers
75
- if not all_values or len(all_values[0]) != (len(semester_data_flat) + 5): # Ensure number of columns matches
76
- headers = ["Họ và tên", "MSV", "Khoa", "Dự báo", "Thời gian"] + [
77
- f"Số môn không thi - HK{i+1}" for i in range(6)] + [
78
- f"Số tín chỉ không thi - HK{i+1}" for i in range(6)] + [
79
- f"Số tín chỉ nợ - HK{i+1}" for i in range(6)] + [
80
- f"Số môn không đạt - HK{i+1}" for i in range(6)] + [
81
- f"Số tín chỉ qua môn - HK{i+1}" for i in range(6)] + [
82
- f"Tổng tín chỉ học kỳ - HK{i+1}" for i in range(6)] + [
83
- f"Số môn học kỳ - HK{i+1}" for i in range(6)] + [
84
- f"Số môn đạt - HK{i+1}" for i in range(6)] + [
85
- f"GPA - HK{i+1}" for i in range(6)] + [
86
- f"Xếp loại - HK{i+1}" for i in range(6)]
87
-
88
- sheet.append_row(headers) # Create headers if missing
89
-
90
- # Append data to the sheet
91
- sheet.append_row(data_row)
92
-
93
-
94
- # ===== List all sheet names =====
95
- # def list_sheet_names(sheet_id):
96
- # client = get_gsheet_client()
97
- # sheet = client.open_by_key(sheet_id)
98
-
99
- # # List all sheet names
100
- # sheet_names = [worksheet.title for worksheet in sheet.worksheets()]
101
- # return sheet_names
102
-
103
-
104
 
105
  # ===== HEADER =====
106
  st.markdown("<h1 style='text-align: center; color: #003366;'>🎓 DỰ ĐOÁN KHẢ NĂNG TỐT NGHIỆP ĐÚNG HẠN</h1>", unsafe_allow_html=True)
107
  st.markdown("<h4 style='text-align: center; color: #666;'>Áp dụng cho sinh viên năm 3</h4>", unsafe_allow_html=True)
108
  st.write("---")
109
 
110
- # ===== SIDEBAR: chọn mô hình =====
111
- model_type = st.sidebar.selectbox("🧠 Chọn mô hình dự báo:", ["Dùng toàn bộ đặc trưng", "Dùng đặc trưng quan trọng"])
112
 
113
- # ===== Giao diện nhập dụ =====
114
- st.subheader("🔢 Chọn dụ mẫu hoặc nhập thông tin cá nhân")
 
 
 
115
 
116
- sample_option = st.selectbox("📝 Chọn ví dụ:", ["Không ví dụ", "Dùng ví dụ mẫu ngành Công nghệ thông tin", "Dùng ví dụ mẫu ngành Kinh tế"])
117
 
118
- # ===== Ví dụ mẫu cho hình "Dùng toàn bộ dữ liệu" =====
119
  sample_cntt_example_full = {
120
  "name": "Nguyễn Văn A",
121
  "student_id": "10117367",
122
  "major": "Công nghệ thông tin",
123
  "semester_data": [
124
- 0, 0, 0, 0, 17, 7, 7, 8.73, 6,
125
- 0, 0, 0, 0, 17, 7, 7, 8.19, 5,
126
- 0, 0, 0, 0, 17, 7, 7, 7.90, 5,
127
- 0, 0, 0, 0, 17, 7, 7, 8.19, 6,
128
- 0, 0, 0, 0, 19, 7, 6, 8.18, 6,
129
- 0, 0, 5, 2, 19, 7, 5, 7.10, 5
130
  ]
131
  }
132
 
133
- # ===== Ví dụ mẫu cho mô hình "Dùng mô hình đơn giản" =====
134
- # ===== Ví dụ cho mô hình "Dùng hình đơn giản" cho Kinh tế =====
135
- sample_kinhte_example_simple = {
136
- "name": "Trần Thị B",
137
- "student_id": "11418092",
138
  "major": "Kinh tế",
139
  "semester_data": [
140
- 17, 0, 7.64, # Học kỳ 1: Số tín chỉ đạt, Số tín chỉ nợ, GPA
141
- 17, 0, 7.19, # Học kỳ 2: Số tín chỉ đạt, Số tín chỉ nợ, GPA
142
- 17, 2, 6.94, # Học kỳ 3: Số tín chỉ đạt, Số tín chỉ nợ, GPA
143
- 17, 0, 7.19, # Học kỳ 4: Số tín chỉ đạt, Số tín chỉ nợ, GPA
144
- 19, 0, 7.65, # Học kỳ 5: Số tín chỉ đạt, Số tín chỉ nợ, GPA
145
- 19, 0, 7.49 # Học kỳ 6: Số tín chỉ đạt, Số tín chỉ nợ, GPA
146
  ]
147
  }
148
 
149
-
150
- # ===== Ví dụ cho mô hình "Dùng mô hình đơn giản" cho CNTT =====
151
- # ===== Ví dụ cho mô hình "Dùng mô hình đơn giản" cho CNTT =====
152
  sample_cntt_example_simple = {
153
  "name": "Nguyễn Văn B",
154
  "student_id": "10117368",
155
  "major": "Công nghệ thông tin",
156
  "semester_data": [
157
- 15, 8, 6.50, # Học kỳ 1: Số tín chỉ đạt, Số tín chỉ nợ, GPA
158
- 17, 15, 6.10, # Học kỳ 2: Số tín chỉ đạt, Số tín chỉ nợ, GPA
159
- 18, 7, 5.90, # Học kỳ 3: Số tín chỉ đạt, Số tín chỉ nợ, GPA
160
- 17, 7, 5.80, # Học kỳ 4: Số tín chỉ đạt, Số tín chỉ nợ, GPA
161
- 19, 8, 6.30, # Học kỳ 5: Số tín chỉ đạt, Số tín chỉ nợ, GPA
162
- 19, 10, 6.20 # Học kỳ 6: Số tín chỉ đạt, Số tín chỉ nợ, GPA
163
  ]
164
  }
165
 
166
- # ===== Ví dụ cho mô hình "Dùng mô hình đơn giản" cho Kinh tế =====
167
- sample_kinhte_example_full = {
168
- "name": "Trần Thị C",
169
- "student_id": "11418093",
170
  "major": "Kinh tế",
171
  "semester_data": [
172
- 0, 0, 0, 0, 16, 6, 6, 7.00, 5,
173
- 0, 0, 0, 0, 18, 7, 7, 8.20, 6,
174
- 0, 0, 0, 0, 17, 7, 7, 7.80, 5,
175
- 0, 0, 0, 0, 17, 7, 6, 7.90, 5,
176
- 0, 0, 0, 0, 19, 8, 5, 8.10, 6,
177
- 0, 0, 8, 2, 19, 7, 6, 7.30, 5
178
  ]
179
  }
180
 
 
 
 
 
 
 
 
 
181
  # ===== Thông tin cá nhân =====
182
  if sample_option == "Dùng ví dụ mẫu ngành Công nghệ thông tin":
183
- name = st.text_input("👤 Họ tên", value=sample_cntt_example_full["name"])
184
- student_id = st.text_input("🎓 Mã sinh viên", value=sample_cntt_example_full["student_id"])
185
- major = st.selectbox("📚 Ngành học", ["Công nghệ thông tin", "Kinh tế"], index=0)
186
  elif sample_option == "Dùng ví dụ mẫu ngành Kinh tế":
187
- name = st.text_input("👤 Họ tên", value=sample_kinhte_example_simple["name"])
188
- student_id = st.text_input("🎓 Mã sinh viên", value=sample_kinhte_example_simple["student_id"])
189
- major = st.selectbox("📚 Ngành học", ["Công nghệ thông tin", "Kinh tế"], index=1)
190
  else:
191
- name = st.text_input("👤 Họ và tên")
192
- student_id = st.text_input("🎓 Mã sinh viên")
193
- major = st.selectbox("📚 Ngành học", ["Công nghệ thông tin", "Kinh tế"])
 
 
 
194
 
195
  st.write("---")
196
 
197
- # ===== Nhập thông tin học kỳ =====
198
- def input_semester(semester_label, default_values=None):
199
- with st.expander(f"📖 {semester_label}", expanded=True):
200
- col1, col2 = st.columns(2)
201
- with col1:
202
- somon0thi = st.number_input("Số môn không thi", 0, value=default_values[0] if default_values else 0, key=f"sm0_{semester_label}")
203
- sotc0thi = st.number_input("Số tín chỉ không thi", 0, value=default_values[1] if default_values else 0, key=f"tc0_{semester_label}")
204
- sotcno = st.number_input("Số tín chỉ nợ", 0, value=default_values[2] if default_values else 0, key=f"tcno_{semester_label}")
205
- mhno = st.number_input("Số môn không đạt", 0, value=default_values[3] if default_values else 0, key=f"mhno_{semester_label}")
206
- try:
207
- default_tc_qua = default_values[4] - default_values[2] if default_values and len(default_values) >= 5 else 0
208
- except:
209
- default_tc_qua = 0
210
- sotc_qua = st.number_input("Số tín chỉ qua môn", 0, value=default_tc_qua, key=f"tcqua_{semester_label}")
211
- with col2:
212
- TCHK = st.number_input("Tổng tín chỉ học kỳ", 0, value=default_values[4] if default_values else 0, key=f"tchk_{semester_label}")
213
- smhk = st.number_input("Số môn học kỳ", 0, value=default_values[5] if default_values else 0, key=f"smhk_{semester_label}")
214
- mhpass = st.number_input("Số môn đạt", 0, value=default_values[6] if default_values else 0, key=f"mhpass_{semester_label}")
215
- TBCHK = st.number_input("GPA", 0.0, 10.0, value=default_values[7] if default_values else 0.0, step=0.01, key=f"gpa_{semester_label}")
216
- xep_loai_selected = st.selectbox("Xếp loại", list(range(7)), index=default_values[8] if default_values else 0, key=f"xeploai_{semester_label}")
217
- return [somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai_selected, sotc_qua]
218
-
219
- def input_important_features(semester_label, default_values=None):
220
- with st.expander(f"📘 {semester_label}", expanded=True):
221
- col1, col2 = st.columns(2)
222
- with col1:
223
- sotc_qua = st.number_input("Số tín chỉ đạt", 0, value=default_values[0] if default_values else 0, key=f"tcqua_imp_{semester_label}")
224
- sotcno = st.number_input("Số tín chỉ nợ", 0, value=default_values[1] if default_values else 0, key=f"tcno_imp_{semester_label}")
225
- with col2:
226
- TBCHK = st.number_input("Điểm trung bình", 0.0, 10.0, value=default_values[2] if default_values else 0.0, step=0.01, key=f"gpa_imp_{semester_label}")
227
- return [sotc_qua, sotcno, TBCHK]
228
-
229
- # ===== Giao diện theo mô hình =====
 
 
 
230
  data = []
231
- semesters = ["HỌC KỲ I", "HỌC KỲ II", "HỌC KỲ III", "HỌC KỲ IV", "HỌC KỲ V", "HỌC KỲ VI"]
232
 
233
- # Mô hình 1: "Dùng toàn bộ dữ liệu"
234
  if model_type == "Dùng toàn bộ đặc trưng":
235
- st.subheader("🔢 Nhập thông tin học kỳ chi tiết")
236
- for idx, sem in enumerate(semesters):
237
- example_data = sample_cntt_example_full if sample_option == "Dùng ví dụ mẫu ngành Công nghệ thông tin" else sample_kinhte_example_full if sample_option == "Dùng ví dụ mẫu ngành Kinh tế" else None
238
- default_values = example_data["semester_data"][idx*9:(idx+1)*9] if example_data else None
239
- data += input_semester(sem, default_values)
240
- nganh = 0 if major == "Công nghệ thông tin" else 1
241
- final_features = np.array(data + [nganh]).reshape(1, -1)
242
-
243
- # Mô hình 2: "Dùng mô hình đơn giản"
244
  else:
245
  st.subheader("✨ Nhập thông tin rút gọn")
246
-
247
- # Allow selecting an example
248
- for idx, sem in enumerate(semesters):
249
- example_data = sample_cntt_example_simple if sample_option == "Dùng ví dụ mẫu ngành Công nghệ thông tin" else sample_kinhte_example_simple if sample_option == "Dùng ví dụ mẫu ngành Kinh tế" else None
250
- default_values = example_data["semester_data"][idx*3:(idx+1)*3] if example_data else None # Fix this line to slice 3 values per semester (Số tín chỉ đạt, Số tín chỉ nợ, GPA)
251
-
252
- # Use expander to group each semester's fields in a collapsible box
253
- if idx < 3: # First row (3 boxes)
254
- with st.expander(f"📘 {sem}", expanded=True):
255
- col1, col2, col3 = st.columns(3) # 3 columns for the first row
256
- with col1:
257
- sotc_qua = st.number_input(f"Số tín chỉ đạt - {sem}", 0, value=default_values[0] if default_values else 0, key=f"tcqua_imp_{sem}")
258
- with col2:
259
- sotcno = st.number_input(f"Số tín chỉ nợ - {sem}", 0, value=default_values[1] if default_values else 0, key=f"tcno_imp_{sem}")
260
- with col3:
261
- TBCHK = st.number_input(f"Điểm trung bình - {sem}", 0.0, 10.0, value=default_values[2] if default_values else 0.0, step=0.01, key=f"gpa_imp_{sem}")
262
- else: # Second row (2 boxes)
263
- with st.expander(f"📘 {sem}", expanded=True):
264
- col1, col2 = st.columns(2) # 2 columns for the second row
265
- with col1:
266
- sotc_qua = st.number_input(f"Số tín chỉ đạt - {sem}", 0, value=default_values[0] if default_values else 0, key=f"tcqua_imp_{sem}")
267
- sotcno = st.number_input(f"Số tín chỉ nợ - {sem}", 0, value=default_values[1] if default_values else 0, key=f"tcno_imp_{sem}")
268
- with col2:
269
- TBCHK = st.number_input(f"Điểm trung bình - {sem}", 0.0, 10.0, value=default_values[2] if default_values else 0.0, step=0.01, key=f"gpa_imp_{sem}")
270
-
271
- # Collect semester data
272
- data += [sotc_qua, sotcno, TBCHK]
273
-
274
  final_features = np.array(data).reshape(1, -1)
275
 
276
- # ===== Predict =====
 
277
  if st.button("🎯 DỰ BÁO"):
278
  if model_type == "Dùng toàn bộ đặc trưng":
279
- prediction = model_full.predict(final_features)
280
- sheet_name = "Trang tính1" # For full data model, save to Trang tính1
281
- if prediction[0] == 0:
282
- # st.success(f"Dự đoán : {prediction[0]}")
283
- st.success(f"🎉 Chúc mừng bạn {name} - {major}! Bạn có khả năng tốt nghiệp đúng hạn!")
284
- st.balloons()
285
  else:
286
- st.error(f"⚠️ Bạn {name} - {major} cần cố gắng hơn! Có nguy cơ trễ hạn.")
287
  st.snow()
288
 
289
  else:
290
- prediction = model_important.predict(final_features)
291
- sheet_name = "Trang tính2" # For full data model, save to Trang tính1
292
- if prediction[0] == 1:
293
- # st.success(f"Dự đoán : {prediction[0]}")
294
- st.success(f"🎉 Chúc mừng bạn {name} - {major}! Bạn có khả năng tốt nghiệp đúng hạn!")
295
- st.balloons()
296
  else:
297
- st.error(f"⚠️ Bạn {name} - {major} cần cố gắng hơn! Có nguy cơ trễ hạn.")
298
  st.snow()
299
-
300
-
301
- # if prediction[0] == 0:
302
- # # st.success(f"Dự đoán là : {prediction[0]}")
303
- # st.success(f"🎉 Chúc mừng bạn {name} - {major}! Bạn có khả năng tốt nghiệp đúng hạn!")
304
- # st.balloons()
305
- # else:
306
- # st.error(f"⚠️ Bạn {name} - {major} cần cố gắng hơn! Có nguy cơ trễ hạn.")
307
- # st.snow()
308
-
309
- # # Debugging: List all sheet names
310
- # sheet_id = "1i7bDNvLVLXN93_e-FN0JLzpg1jb64Z_aEuyPjIfwbdQ" # Use your actual Spreadsheet ID
311
- # sheet_names = list_sheet_names(sheet_id)
312
- # st.write("Available sheet names:", sheet_names)
313
-
314
- # Ghi log lên Google Sheets
315
- save_to_gsheet(name, student_id, major, prediction, data,sheet_name) # Pass data to save function
 
1
  import streamlit as st
2
  import numpy as np
3
  import joblib
 
 
 
 
4
 
5
  # ===== Load models =====
6
  model_full = joblib.load("random_forest_model_full.pkl")
 
16
  font-family: 'Poppins', sans-serif;
17
  }
18
  .block-container {
19
+ padding: 2rem;
20
  }
21
  .stButton button {
22
  background: linear-gradient(90deg, #4F8BF9 0%, #8E2DE2 100%);
 
30
  </style>
31
  """, unsafe_allow_html=True)
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  # ===== HEADER =====
35
  st.markdown("<h1 style='text-align: center; color: #003366;'>🎓 DỰ ĐOÁN KHẢ NĂNG TỐT NGHIỆP ĐÚNG HẠN</h1>", unsafe_allow_html=True)
36
  st.markdown("<h4 style='text-align: center; color: #666;'>Áp dụng cho sinh viên năm 3</h4>", unsafe_allow_html=True)
37
  st.write("---")
38
 
 
 
39
 
40
+ # ===== SIDEBAR: chọn hình =====
41
+ model_type = st.sidebar.selectbox("🧠 Chọn hình dự báo:", [
42
+ "Dùng toàn bộ đặc trưng",
43
+ "Dùng đặc trưng quan trọng"
44
+ ])
45
 
 
46
 
47
+ # ===== Ví dụ mẫu cho FULL MODEL (9 feature/kỳ) =====
48
  sample_cntt_example_full = {
49
  "name": "Nguyễn Văn A",
50
  "student_id": "10117367",
51
  "major": "Công nghệ thông tin",
52
  "semester_data": [
53
+ 0,0,0,0,17,7,7,8.73,6,
54
+ 0,0,0,0,17,7,7,8.19,5,
55
+ 0,0,0,0,17,7,7,7.90,5,
56
+ 0,0,0,0,17,7,7,8.19,6,
57
+ 0,0,0,0,19,7,6,8.18,6,
58
+ 0,0,0,0,19,7,5,7.10,5
59
  ]
60
  }
61
 
62
+ sample_kinhte_example_full = {
63
+ "name": "Trần Thị C",
64
+ "student_id": "11418093",
 
 
65
  "major": "Kinh tế",
66
  "semester_data": [
67
+ 0,0,0,0,16,6,6,7.00,5,
68
+ 0,0,0,0,18,7,7,8.20,6,
69
+ 0,0,0,0,17,7,7,7.80,5,
70
+ 0,0,0,0,17,7,6,7.90,5,
71
+ 0,0,0,0,19,8,5,8.10,6,
72
+ 0,0,8,2,19,7,6,7.30,5
73
  ]
74
  }
75
 
76
+ # ===== Ví dụ cho SIMPLE MODEL (3 feature/kỳ) =====
 
 
77
  sample_cntt_example_simple = {
78
  "name": "Nguyễn Văn B",
79
  "student_id": "10117368",
80
  "major": "Công nghệ thông tin",
81
  "semester_data": [
82
+ 15,8,6.50,
83
+ 17,15,6.10,
84
+ 18,7,5.90,
85
+ 17,7,5.80,
86
+ 19,8,6.30,
87
+ 19,10,6.20
88
  ]
89
  }
90
 
91
+ sample_kinhte_example_simple = {
92
+ "name": "Trần Thị B",
93
+ "student_id": "11418092",
 
94
  "major": "Kinh tế",
95
  "semester_data": [
96
+ 17,0,7.64,
97
+ 17,0,7.19,
98
+ 17,2,6.94,
99
+ 17,0,7.19,
100
+ 19,0,7.65,
101
+ 19,0,7.49
102
  ]
103
  }
104
 
105
+
106
+ # ===== CHỌN VÍ DỤ =====
107
+ sample_option = st.selectbox("📝 Chọn ví dụ:", [
108
+ "Không ví dụ",
109
+ "Dùng ví dụ mẫu ngành Công nghệ thông tin",
110
+ "Dùng ví dụ mẫu ngành Kinh tế"
111
+ ])
112
+
113
  # ===== Thông tin cá nhân =====
114
  if sample_option == "Dùng ví dụ mẫu ngành Công nghệ thông tin":
115
+ example = sample_cntt_example_full if model_type == "Dùng toàn bộ đặc trưng" else sample_cntt_example_simple
 
 
116
  elif sample_option == "Dùng ví dụ mẫu ngành Kinh tế":
117
+ example = sample_kinhte_example_full if model_type == "Dùng toàn bộ đặc trưng" else sample_kinhte_example_simple
 
 
118
  else:
119
+ example = None
120
+
121
+ name = st.text_input("👤 Họ và tên", value=example["name"] if example else "")
122
+ student_id = st.text_input("🎓 Mã sinh viên", value=example["student_id"] if example else "")
123
+ major = st.selectbox("📚 Ngành học", ["Công nghệ thông tin", "Kinh tế"],
124
+ index=0 if not example else (0 if example["major"] == "Công nghệ thông tin" else 1))
125
 
126
  st.write("---")
127
 
128
+
129
+ # ===== HÀM NHẬP DỮ LIỆU =====
130
+ def input_full_semester(label, default):
131
+ with st.expander(label, expanded=True):
132
+ results = []
133
+ fields = [
134
+ "Số môn không thi", "Số tín chỉ không thi", "Số tín chỉ nợ", "Số môn không đạt",
135
+ "Tổng tín chỉ học kỳ", "Số môn học kỳ", "Số môn đạt", "GPA", "Xếp loại"
136
+ ]
137
+
138
+ col1, col2, col3 = st.columns(3)
139
+ for i, field in enumerate(fields):
140
+ value = default[i] if default else 0
141
+ with (col1 if i < 3 else col2 if i < 6 else col3):
142
+ if i == 7:
143
+ value = st.number_input(f"{field}", 0.0, 10.0, value=float(value), step=0.01)
144
+ elif i == 8:
145
+ value = st.selectbox(f"{field}", list(range(7)), index=value)
146
+ else:
147
+ value = st.number_input(f"{field}", 0, value=value)
148
+ results.append(value)
149
+
150
+ return results
151
+
152
+
153
+ def input_simple_semester(label, default):
154
+ with st.expander(label, expanded=True):
155
+ col1, col2, col3 = st.columns(3)
156
+ sotc_qua = col1.number_input(f"Số tín chỉ đạt - {label}", 0, value=default[0] if default else 0)
157
+ sotc_no = col2.number_input(f"Số tín chỉ nợ - {label}", 0, value=default[1] if default else 0)
158
+ gpa = col3.number_input(f"GPA - {label}", 0.0, 10.0, value=default[2] if default else 0.0, step=0.01)
159
+ return [sotc_qua, sotc_no, gpa]
160
+
161
+
162
+ # ===== NHẬP DỮ LIỆU =====
163
+ semesters = ["HỌC KỲ I","HỌC KỲ II","HỌC KỲ III","HỌC KỲ IV","HỌC KỲ V","HỌC KỲ VI"]
164
  data = []
 
165
 
 
166
  if model_type == "Dùng toàn bộ đặc trưng":
167
+ st.subheader("🔢 Nhập thông tin đầy đủ 6 học kỳ")
168
+
169
+ for i, sem in enumerate(semesters):
170
+ default_values = example["semester_data"][i*9:(i+1)*9] if example else None
171
+ data += input_full_semester(sem, default_values)
172
+
173
+ final_features = np.array(data).reshape(1, -1)
174
+
 
175
  else:
176
  st.subheader("✨ Nhập thông tin rút gọn")
177
+
178
+ for i, sem in enumerate(semesters):
179
+ default_values = example["semester_data"][i*3:(i+1)*3] if example else None
180
+ data += input_simple_semester(sem, default_values)
181
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  final_features = np.array(data).reshape(1, -1)
183
 
184
+
185
+ # ===== PREDICT =====
186
  if st.button("🎯 DỰ BÁO"):
187
  if model_type == "Dùng toàn bộ đặc trưng":
188
+ prediction = model_full.predict(final_features)[0]
189
+
190
+ if prediction == 0: # 0 = tốt nghiệp đúng hạn (theo mô hình của bạn)
191
+ st.success(f"🎉 Chúc mừng {name}! Bạn có khả năng tốt nghiệp đúng hạn!")
192
+ st.balloons()
 
193
  else:
194
+ st.error(f"⚠️ Bạn nguy trễ hạn, cần cố gắng hơn!")
195
  st.snow()
196
 
197
  else:
198
+ prediction = model_important.predict(final_features)[0]
199
+
200
+ if prediction == 1: # 1 = đúng hạn trong simple model
201
+ st.success(f"🎉 Chúc mừng {name}! Bạn có khả năng tốt nghiệp đúng hạn!")
202
+ st.balloons()
 
203
  else:
204
+ st.error(f"⚠️ Bạn nguy trễ hạn, cần cố gắng hơn!")
205
  st.snow()