namngo commited on
Commit
edbeda5
·
verified ·
1 Parent(s): 2729472

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +115 -251
app.py CHANGED
@@ -66,21 +66,17 @@ def save_to_gsheet(name, student_id, major, prediction, semester_data, sheet_nam
66
  # Get the current date and time
67
  now = datetime.now()
68
  current_time = now.strftime("%Y-%m-%d %H:%M:%S")
69
-
70
  # Ensure prediction is in the expected format (0 or 1)
71
  if isinstance(prediction, np.ndarray):
72
  prediction = int(prediction[0]) # Convert to int if it's ndarray
 
73
  elif isinstance(prediction, np.int64):
74
  prediction = int(prediction) # Convert np.int64 to int
75
-
76
- # Flatten semester data to individual columns for each semester
77
- # Ensure all data points are included, considering the structure varies by model
78
- # For 'full' model, semester_data has 9 values per semester * 6 semesters = 54 values
79
- # For 'important' model, semester_data has 3 values per semester * 6 semesters = 18 values
80
- # We need to handle both cases for saving. Pad with empty strings if using the simple model data for the full sheet structure.
81
 
 
82
  semester_data_flat = [str(val) for val in semester_data] # Convert all semester data values to strings
83
-
84
  # Create a data row to insert into the sheet
85
  data_row = [name, student_id, major, prediction, current_time] + semester_data_flat
86
 
@@ -94,316 +90,186 @@ def save_to_gsheet(name, student_id, major, prediction, semester_data, sheet_nam
94
  # Get all values from the sheet to check if the first row is empty (i.e., headers not created yet)
95
  all_values = sheet.get_all_values()
96
 
97
- # Define headers based on sheet name (model type)
98
- if sheet_name == "Trang tính1": # Full model sheet
99
- expected_cols = 5 + (9 * 6) # 5 personal + 9 features per semester * 6 semesters
100
- headers = ["Họ và tên", "MSV", "Khoa", "Dự báo", "Thời gian"] + [
101
  f"Số môn không thi - HK{i+1}" for i in range(6)] + [
102
  f"Số tín chỉ không thi - HK{i+1}" for i in range(6)] + [
103
  f"Số tín chỉ nợ - HK{i+1}" for i in range(6)] + [
104
  f"Số môn không đạt - HK{i+1}" for i in range(6)] + [
 
105
  f"Tổng tín chỉ học kỳ - HK{i+1}" for i in range(6)] + [
106
  f"Số môn học kỳ - HK{i+1}" for i in range(6)] + [
107
  f"Số môn đạt - HK{i+1}" for i in range(6)] + [
108
  f"GPA - HK{i+1}" for i in range(6)] + [
109
  f"Xếp loại - HK{i+1}" for i in range(6)]
110
- elif sheet_name == "Trang tính2": # Important features model sheet
111
- expected_cols = 5 + (3 * 6) # 5 personal + 3 features per semester * 6 semesters
112
- headers = ["Họ và tên", "MSV", "Khoa", "Dự báo", "Thời gian"] + [
113
- f"Số tín chỉ đạt - HK{i+1}" for i in range(6)] + [
114
- f"Số tín chỉ nợ - HK{i+1}" for i in range(6)] + [
115
- f"Điểm trung bình - HK{i+1}" for i in range(6)]
116
- else: # Fallback or other sheets
117
- expected_cols = 5 + len(semester_data_flat)
118
- headers = ["Họ và tên", "MSV", "Khoa", "Dự báo", "Thời gian"] + [f"Data Col {i+1}" for i in range(len(semester_data_flat))]
119
-
120
- # If the sheet is empty or if headers are missing or mismatched column count, insert headers
121
- if not all_values or len(all_values[0]) != expected_cols:
122
- # Clear existing content if columns don't match to prevent misalignment
123
- if all_values:
124
- sheet.clear()
125
- sheet.append_row(headers) # Create headers if missing or mismatch
126
-
127
- # Pad data_row with empty strings if it doesn't match the expected columns (e.g., saving simple data to full sheet)
128
- # Or truncate if somehow too long (less likely)
129
- if len(data_row) < expected_cols:
130
- data_row.extend([''] * (expected_cols - len(data_row)))
131
- elif len(data_row) > expected_cols:
132
- data_row = data_row[:expected_cols]
133
-
134
  # Append data to the sheet
135
  sheet.append_row(data_row)
136
 
 
137
  # ===== List all sheet names =====
138
- def list_sheet_names(sheet_id):
139
- client = get_gsheet_client()
140
- sheet = client.open_by_key(sheet_id)
141
- # List all sheet names
142
- sheet_names = [worksheet.title for worksheet in sheet.worksheets()]
143
- return sheet_names
 
 
 
144
 
145
  # ===== HEADER =====
146
- st.markdown("🎓 DỰ ĐOÁN KHẢ NĂNG TỐT NGHIỆP ĐÚNG HẠN", unsafe_allow_html=True)
147
- st.markdown("Áp dụng cho sinh viên năm 3", unsafe_allow_html=True)
148
  st.write("---")
149
 
150
  # ===== SIDEBAR: chọn mô hình =====
151
  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"])
152
 
153
- # ===== Giao diện nhập ví dụ và thông tin cá nhân (using columns) =====
154
  st.subheader("🔢 Chọn ví dụ mẫu hoặc nhập thông tin cá nhân")
155
 
156
- # Define example data
 
 
157
  sample_cntt_example_full = {
158
  "name": "Nguyễn Văn A",
159
  "student_id": "10117367",
160
  "major": "Công nghệ thông tin",
161
  "semester_data": [
162
- 0, 0, 0, 0, 17, 7, 7, 8.73, 0, # HK1
163
- 0, 0, 0, 0, 17, 7, 7, 8.19, 0, # HK2
164
- 0, 0, 0, 0, 17, 7, 7, 7.90, 0, # HK3
165
- 0, 0, 0, 0, 17, 7, 7, 8.19, 0, # HK4
166
- 0, 0, 0, 0, 19, 7, 6, 8.18, 0, # HK5
167
- 0, 0, 5, 2, 19, 7, 5, 7.10, 1 # HK6
168
  ]
169
  }
170
 
171
- sample_kinhte_example_full = {
172
- "name": "Trần Thị C",
173
- "student_id": "11418093",
 
 
174
  "major": "Kinh tế",
175
  "semester_data": [
176
- 0, 0, 0, 0, 16, 6, 6, 7.00, 1, # HK1
177
- 0, 0, 0, 0, 18, 7, 7, 8.20, 1, # HK2
178
- 0, 0, 0, 0, 17, 7, 7, 7.80, 1, # HK3
179
- 0, 0, 0, 0, 17, 7, 6, 7.90, 1, # HK4
180
- 0, 0, 0, 0, 19, 8, 5, 8.10, 0, # HK5
181
- 0, 0, 8, 2, 19, 7, 6, 7.30, 1 # HK6
182
  ]
183
  }
184
 
 
 
 
185
  sample_cntt_example_simple = {
186
  "name": "Nguyễn Văn B",
187
  "student_id": "10117368",
188
  "major": "Công nghệ thông tin",
189
  "semester_data": [
190
- 15, 8, 7.50, # HK1: Số tín chỉ đạt, Số tín chỉ nợ, GPA
191
- 17, 7, 8.10, # HK2: Số tín chỉ đạt, Số tín chỉ nợ, GPA
192
- 18, 7, 7.90, # HK3: Số tín chỉ đạt, Số tín chỉ nợ, GPA
193
- 17, 7, 7.80, # HK4: Số tín chỉ đạt, Số tín chỉ nợ, GPA
194
- 19, 8, 8.30, # HK5: Số tín chỉ đạt, Số tín chỉ nợ, GPA
195
- 19, 7, 7.20 # HK6: Số tín chỉ đạt, Số tín chỉ nợ, GPA
196
  ]
197
  }
198
 
199
- sample_kinhte_example_simple = {
200
- "name": "Trần Thị B",
201
- "student_id": "11418092",
 
202
  "major": "Kinh tế",
203
  "semester_data": [
204
- 17, 7, 7.64, # HK1: Số tín chỉ đạt, Số tín chỉ nợ, GPA
205
- 17, 7, 7.19, # HK2: Số tín chỉ đạt, Số tín chỉ nợ, GPA
206
- 17, 7, 6.94, # HK3: Số tín chỉ đạt, Số tín chỉ nợ, GPA
207
- 17, 7, 7.19, # HK4: Số tín chỉ đạt, Số tín chỉ nợ, GPA
208
- 19, 7, 7.65, # HK5: Số tín chỉ đạt, Số tín chỉ nợ, GPA
209
- 19, 7, 7.49 # HK6: Số tín chỉ đạt, Số tín chỉ nợ, GPA
210
  ]
211
  }
212
 
213
-
214
- # Use columns for layout
215
- col_sample, col_name, col_id, col_major = st.columns([0.3, 0.3, 0.2, 0.2]) # Adjust column widths as needed
216
-
217
- with col_sample:
218
- 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ế"])
219
-
220
- # Determine default values based on sample_option BEFORE creating text_inputs and selectbox
221
- default_name = ""
222
- default_student_id = ""
223
- default_major_index = 0 # Default to CNTT
224
-
225
  if sample_option == "Dùng ví dụ mẫu ngành Công nghệ thông tin":
226
- if model_type == "Dùng toàn bộ đặc trưng":
227
- default_name = sample_cntt_example_full["name"]
228
- default_student_id = sample_cntt_example_full["student_id"]
229
- # default_major_index is already 0 for CNTT
230
- else: # Dùng đặc trưng quan trọng
231
- default_name = sample_cntt_example_simple["name"]
232
- default_student_id = sample_cntt_example_simple["student_id"]
233
- # default_major_index is already 0 for CNTT
234
-
235
  elif sample_option == "Dùng ví dụ mẫu ngành Kinh tế":
236
- if model_type == "Dùng toàn bộ đặc trưng":
237
- default_name = sample_kinhte_example_full["name"]
238
- default_student_id = sample_kinhte_example_full["student_id"]
239
- default_major_index = 1 # Index for Kinh tế
240
- else: # Dùng đặc trưng quan trọng
241
- default_name = sample_kinhte_example_simple["name"]
242
- default_student_id = sample_kinhte_example_simple["student_id"]
243
- default_major_index = 1 # Index for Kinh tế
244
-
245
- # Place inputs in columns using determined default values
246
- with col_name:
247
- name = st.text_input("👤 Họ và tên", value=default_name)
248
-
249
- with col_id:
250
- student_id = st.text_input("🎓 Mã sinh viên", value=default_student_id)
251
-
252
- with col_major:
253
- major = st.selectbox("📚 Ngành học", ["Công nghệ thông tin", "Kinh tế"], index=default_major_index)
254
-
255
 
256
  st.write("---")
257
 
258
  # ===== Nhập thông tin học kỳ =====
259
  def input_semester(semester_label, default_values=None):
260
- # Ensure default_values is a list of the correct length (9) or None
261
- if default_values is None or len(default_values) != 9:
262
- default_values = [0] * 9 # Provide default zeros if not provided or length mismatch
263
-
264
  with st.expander(f"📖 {semester_label}", expanded=True):
265
  col1, col2 = st.columns(2)
266
  with col1:
267
- somon0thi = st.number_input("Số môn không thi", 0, value=default_values[0], key=f"sm0_{semester_label}")
268
- sotc0thi = st.number_input("Số tín chỉ không thi", 0, value=default_values[1], key=f"tc0_{semester_label}")
269
- sotcno = st.number_input("Số tín chỉ nợ", 0, value=default_values[2], key=f"tcno_{semester_label}")
270
- mhno = st.number_input("Số môn không đạt", 0, value=default_values[3], key=f"mhno_{semester_label}")
271
- # Calculate default_tc_qua from TCHK (index 4) and Sotcno (index 2) if available
272
  try:
273
- # The original code calculated default_tc_qua from TCHK and Sotcno, but the example data
274
- # structure doesn't align with this directly. Let's stick to the example data's structure (which includes sotc_qua implicitly in some sense?)
275
- # Reverting to original logic based on example data structure indices
276
- default_tc_qua_val = default_values[4] - default_values[2] # Assuming TCHK - Sotcno
277
- except (IndexError, TypeError):
278
- default_tc_qua_val = 0 # Fallback
279
-
280
-
281
- # Re-evaluating based on the example data structure: the example data for full model
282
- # has 9 elements per semester, ordered as:
283
- # somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai_selected
284
- # sotc_qua (số tín chỉ qua môn) is NOT explicitly in the example data structure of 9 elements.
285
- # It seems like sotc_qua was intended to be calculated or is a different feature.
286
- # The original code calculates default_tc_qua = default_values[4] - default_values[2] (TCHK - Sotcno)
287
- # Let's keep this calculation for default value, but the returned list will contain 10 elements.
288
- # The saved GSheet headers suggest 10 features per semester. Let's align the input and saving.
289
- # The input fields are 9. Let's assume sotc_qua is derived or implicitly part of the 9 for the model input.
290
- # However, the GSheet saving code expects 10 values *per semester* for the full model!
291
- # It expects: somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai, sotc_qua
292
- # The input only has 9. Let's add an input for sotc_qua and return 10 values.
293
-
294
- # Let's fix the input and return value to have 10 features per semester for the full model
295
- # The example data only has 9 values. This means the example data is missing 'sotc_qua'.
296
- # We need to adjust the input_semester function and the example data handling.
297
- # Assuming sotc_qua = TCHK - sotcno is the intended feature.
298
- # Let's add it as an input field for clarity and consistency with GSheet saving.
299
- # The example data will need a placeholder for sotc_qua.
300
- # Let's recalculate the example data structures to include a 10th value (sotc_qua).
301
- # For existing examples: sotc_qua = TCHK - sotcno
302
-
303
- # Re-calculating example data to have 10 features per semester for 'full' model:
304
- # original: somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai (9 features)
305
- # new: somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai, sotc_qua (10 features)
306
- # where sotc_qua = TCHK - sotcno
307
-
308
- recalculated_cntt_full_data = []
309
- for i in range(6):
310
- sem_slice = sample_cntt_example_full["semester_data"][i*9:(i+1)*9]
311
- somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai = sem_slice
312
- sotc_qua_val = TCHK - sotcno
313
- recalculated_cntt_full_data.extend([somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai, sotc_qua_val])
314
-
315
- recalculated_kinhte_full_data = []
316
- for i in range(6):
317
- sem_slice = sample_kinhte_example_full["semester_data"][i*9:(i+1)*9]
318
- somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai = sem_slice
319
- sotc_qua_val = TCHK - sotcno
320
- recalculated_kinhte_full_data.extend([somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai, sotc_qua_val])
321
-
322
- # Update the input function to use the 10th value as default for sotc_qua
323
- # Ensure default_values has 10 elements
324
- if default_values is None or len(default_values) != 10:
325
- default_values = [0] * 10 # Provide default zeros if not provided or length mismatch
326
-
327
- somon0thi = st.number_input("Số môn không thi", 0, value=default_values[0], key=f"sm0_{semester_label}")
328
- sotc0thi = st.number_input("Số tín chỉ không thi", 0, value=default_values[1], key=f"tc0_{semester_label}")
329
- sotcno = st.number_input("Số tín chỉ nợ", 0, value=default_values[2], key=f"tcno_{semester_label}")
330
- mhno = st.number_input("Số môn không đạt", 0, value=default_values[3], key=f"mhno_{semester_label}")
331
- # sotc_qua input field
332
- sotc_qua = st.number_input("Số tín chỉ qua môn", 0, value=default_values[9], key=f"tcqua_{semester_label}") # Use index 9 for sotc_qua
333
-
334
- with col2:
335
- TCHK = st.number_input("Tổng tín chỉ học kỳ", 0, value=default_values[4], key=f"tchk_{semester_label}")
336
- smhk = st.number_input("Số môn học kỳ", 0, value=default_values[5], key=f"smhk_{semester_label}")
337
- mhpass = st.number_input("Số môn đạt", 0, value=default_values[6], key=f"mhpass_{semester_label}")
338
- TBCHK = st.number_input("GPA", 0.0, 10.0, value=float(default_values[7]), step=0.01, key=f"gpa_{semester_label}")
339
- xep_loai_selected = st.selectbox("Xếp loại", list(range(7)), index=int(default_values[8]), key=f"xeploai_{semester_label}")
340
-
341
-
342
- # Return 10 values in the correct order for GSheet saving and model input
343
- return [somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai_selected, sotc_qua]
344
-
345
 
346
  def input_important_features(semester_label, default_values=None):
347
- # Ensure default_values is a list of the correct length (3) or None
348
- if default_values is None or len(default_values) != 3:
349
- default_values = [0] * 3 # Provide default zeros if not provided or length mismatch
350
-
351
  with st.expander(f"📘 {semester_label}", expanded=True):
352
  col1, col2 = st.columns(2)
353
  with col1:
354
- # Assuming the order in example_simple is: Số tín chỉ đạt, Số tín chỉ nợ, GPA
355
- sotc_qua = st.number_input("Số tín chỉ đạt", 0, value=default_values[0], key=f"tcqua_imp_{semester_label}")
356
- sotcno = st.number_input("Số tín chỉ nợ", 0, value=default_values[1], key=f"tcno_imp_{semester_label}")
357
-
358
  with col2:
359
- TBCHK = st.number_input("Điểm trung bình", 0.0, 10.0, value=float(default_values[2]), step=0.01, key=f"gpa_imp_{semester_label}")
360
-
361
- return [sotc_qua, sotcno, TBCHK]
362
 
363
  # ===== Giao diện theo mô hình =====
364
  data = []
365
  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"]
366
 
367
- # Mô hình 1: "Dùng toàn bộ đặc trưng"
368
  if model_type == "Dùng toàn bộ đặc trưng":
369
- st.subheader("🔢 Nhập thông tin học kỳ chi tiết (10 đặc trưng/học kỳ)")
370
  for idx, sem in enumerate(semesters):
371
- # Select example data based on sample_option and model_type
372
- if sample_option == "Dùng dụ mẫu ngành Công nghệ thông tin":
373
- example_data_sem = recalculated_cntt_full_data # Use recalculated data with 10 features
374
- elif sample_option == "Dùng ví dụ mẫu ngành Kinh tế":
375
- example_data_sem = recalculated_kinhte_full_data # Use recalculated data with 10 features
376
- else:
377
- example_data_sem = None # No example
378
-
379
- # Get default values for the current semester (10 values)
380
- default_values = example_data_sem[idx*10:(idx+1)*10] if example_data_sem else None
381
-
382
  data += input_semester(sem, default_values)
383
-
384
- # The 'nganh' feature (0 for CNTT, 1 for Kinh tế) is needed for the full model
385
  nganh = 0 if major == "Công nghệ thông tin" else 1
386
- # The model expects [semester1_features..., semester6_features..., nganh]
387
  final_features = np.array(data + [nganh]).reshape(1, -1)
388
 
389
- # Mô hình 2: "Dùng đặc trưng quan trọng"
390
  else:
391
- st.subheader("✨ Nhập thông tin rút gọn (3 đặc trưng/học kỳ)")
 
 
 
 
392
  for idx, sem in enumerate(semesters):
393
- # Select example data based on sample_option and model_type
394
- if sample_option == "Dùng dụ mẫu ngành Công nghệ thông tin":
395
- example_data_sem = sample_cntt_example_simple["semester_data"]
396
- elif sample_option == "Dùng ví dụ mẫu ngành Kinh tế":
397
- example_data_sem = sample_kinhte_example_simple["semester_data"]
398
- else:
399
- example_data_sem = None # No example
400
-
401
- # Get default values for the current semester (3 values)
402
- default_values = example_data_sem[idx*3:(idx+1)*3] if example_data_sem else None
403
-
404
  data += input_important_features(sem, default_values)
405
-
406
- # The simple model likely does not use the 'nganh' feature, based on the original code's final_features construction
407
  final_features = np.array(data).reshape(1, -1)
408
 
409
  # ===== Predict =====
@@ -411,9 +277,11 @@ if st.button("🎯 DỰ BÁO"):
411
  if model_type == "Dùng toàn bộ đặc trưng":
412
  prediction = model_full.predict(final_features)
413
  sheet_name = "Trang tính1" # For full data model, save to Trang tính1
414
- else: # Dùng đặc trưng quan trọng
 
415
  prediction = model_important.predict(final_features)
416
- sheet_name = "Trang tính2" # For important features model, save to Trang tính2
 
417
 
418
  if prediction[0] == 1:
419
  st.success(f"🎉 Chúc mừng bạn {name} - {major}! Bạn có khả năng tốt nghiệp đúng hạn!")
@@ -422,14 +290,10 @@ if st.button("🎯 DỰ BÁO"):
422
  st.error(f"⚠️ Bạn {name} - {major} cần cố gắng hơn! Có nguy cơ trễ hạn.")
423
  st.snow()
424
 
 
 
 
 
 
425
  # Ghi log lên Google Sheets
426
- # Pass the relevant data based on the selected model for saving
427
- if model_type == "Dùng toàn bộ đặc trưng":
428
- # Need to pass the 10 features per semester + nganh (total 61 features)
429
- # The 'data' list currently holds 60 features (10*6). Add 'nganh' to the data list for saving.
430
- data_to_save = data + [nganh]
431
- else: # Dùng đặc trưng quan trọng
432
- # The 'data' list holds 18 features (3*6).
433
- data_to_save = data
434
-
435
- save_to_gsheet(name, student_id, major, prediction, data_to_save, sheet_name) # Pass data_to_save
 
66
  # Get the current date and time
67
  now = datetime.now()
68
  current_time = now.strftime("%Y-%m-%d %H:%M:%S")
69
+
70
  # Ensure prediction is in the expected format (0 or 1)
71
  if isinstance(prediction, np.ndarray):
72
  prediction = int(prediction[0]) # Convert to int if it's ndarray
73
+
74
  elif isinstance(prediction, np.int64):
75
  prediction = int(prediction) # Convert np.int64 to int
 
 
 
 
 
 
76
 
77
+ # Flatten semester data to individual columns for each semester
78
  semester_data_flat = [str(val) for val in semester_data] # Convert all semester data values to strings
79
+
80
  # Create a data row to insert into the sheet
81
  data_row = [name, student_id, major, prediction, current_time] + semester_data_flat
82
 
 
90
  # Get all values from the sheet to check if the first row is empty (i.e., headers not created yet)
91
  all_values = sheet.get_all_values()
92
 
93
+ # If the sheet is empty or if headers are missing, insert headers
94
+ if not all_values or len(all_values[0]) != (len(semester_data_flat) + 5): # Ensure number of columns matches
95
+ headers = ["Họ tên", "MSV", "Khoa", "Dự báo", "Thời gian"] + [
 
96
  f"Số môn không thi - HK{i+1}" for i in range(6)] + [
97
  f"Số tín chỉ không thi - HK{i+1}" for i in range(6)] + [
98
  f"Số tín chỉ nợ - HK{i+1}" for i in range(6)] + [
99
  f"Số môn không đạt - HK{i+1}" for i in range(6)] + [
100
+ f"Số tín chỉ qua môn - HK{i+1}" for i in range(6)] + [
101
  f"Tổng tín chỉ học kỳ - HK{i+1}" for i in range(6)] + [
102
  f"Số môn học kỳ - HK{i+1}" for i in range(6)] + [
103
  f"Số môn đạt - HK{i+1}" for i in range(6)] + [
104
  f"GPA - HK{i+1}" for i in range(6)] + [
105
  f"Xếp loại - HK{i+1}" for i in range(6)]
106
+
107
+ sheet.append_row(headers) # Create headers if missing
108
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  # Append data to the sheet
110
  sheet.append_row(data_row)
111
 
112
+
113
  # ===== List all sheet names =====
114
+ # def list_sheet_names(sheet_id):
115
+ # client = get_gsheet_client()
116
+ # sheet = client.open_by_key(sheet_id)
117
+
118
+ # # List all sheet names
119
+ # sheet_names = [worksheet.title for worksheet in sheet.worksheets()]
120
+ # return sheet_names
121
+
122
+
123
 
124
  # ===== HEADER =====
125
+ 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)
126
+ st.markdown("<h4 style='text-align: center; color: #666;'>Áp dụng cho sinh viên năm 3</h4>", unsafe_allow_html=True)
127
  st.write("---")
128
 
129
  # ===== SIDEBAR: chọn mô hình =====
130
  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"])
131
 
132
+ # ===== Giao diện nhập ví dụ =====
133
  st.subheader("🔢 Chọn ví dụ mẫu hoặc nhập thông tin cá nhân")
134
 
135
+ 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ế"])
136
+
137
+ # ===== Ví dụ mẫu cho mô hình "Dùng toàn bộ dữ liệu" =====
138
  sample_cntt_example_full = {
139
  "name": "Nguyễn Văn A",
140
  "student_id": "10117367",
141
  "major": "Công nghệ thông tin",
142
  "semester_data": [
143
+ 0, 0, 0, 0, 17, 7, 7, 8.73, 0,
144
+ 0, 0, 0, 0, 17, 7, 7, 8.19, 0,
145
+ 0, 0, 0, 0, 17, 7, 7, 7.90, 0,
146
+ 0, 0, 0, 0, 17, 7, 7, 8.19, 0,
147
+ 0, 0, 0, 0, 19, 7, 6, 8.18, 0,
148
+ 0, 0, 5, 2, 19, 7, 5, 7.10, 1
149
  ]
150
  }
151
 
152
+ # ===== Ví dụ mẫu cho mô hình "Dùng mô hình đơn giản" =====
153
+ # ===== Ví dụ cho mô hình "Dùng mô hình đơn giản" cho Kinh tế =====
154
+ sample_kinhte_example_simple = {
155
+ "name": "Trần Thị B",
156
+ "student_id": "11418092",
157
  "major": "Kinh tế",
158
  "semester_data": [
159
+ 17, 7, 7.64, # Học kỳ 1: Số tín chỉ đạt, Số tín chỉ nợ, GPA
160
+ 17, 7, 7.19, # Học kỳ 2: Số tín chỉ đạt, Số tín chỉ nợ, GPA
161
+ 17, 7, 6.94, # Học kỳ 3: Số tín chỉ đạt, Số tín chỉ nợ, GPA
162
+ 17, 7, 7.19, # Học kỳ 4: Số tín chỉ đạt, Số tín chỉ nợ, GPA
163
+ 19, 7, 7.65, # Học kỳ 5: Số tín chỉ đạt, Số tín chỉ nợ, GPA
164
+ 19, 7, 7.49 # Học kỳ 6: Số tín chỉ đạt, Số tín chỉ nợ, GPA
165
  ]
166
  }
167
 
168
+
169
+ # ===== Ví dụ cho mô hình "Dùng mô hình đơn giản" cho CNTT =====
170
+ # ===== Ví dụ cho mô hình "Dùng mô hình đơn giản" cho CNTT =====
171
  sample_cntt_example_simple = {
172
  "name": "Nguyễn Văn B",
173
  "student_id": "10117368",
174
  "major": "Công nghệ thông tin",
175
  "semester_data": [
176
+ 15, 8, 7.50, # Học kỳ 1: Số tín chỉ đạt, Số tín chỉ nợ, GPA
177
+ 17, 7, 8.10, # Học kỳ 2: Số tín chỉ đạt, Số tín chỉ nợ, GPA
178
+ 18, 7, 7.90, # Học kỳ 3: Số tín chỉ đạt, Số tín chỉ nợ, GPA
179
+ 17, 7, 7.80, # Học kỳ 4: Số tín chỉ đạt, Số tín chỉ nợ, GPA
180
+ 19, 8, 8.30, # Học kỳ 5: Số tín chỉ đạt, Số tín chỉ nợ, GPA
181
+ 19, 7, 7.20 # Học kỳ 6: Số tín chỉ đạt, Số tín chỉ nợ, GPA
182
  ]
183
  }
184
 
185
+ # ===== Ví dụ cho mô hình "Dùng mô hình đơn giản" cho Kinh tế =====
186
+ sample_kinhte_example_full = {
187
+ "name": "Trần Thị C",
188
+ "student_id": "11418093",
189
  "major": "Kinh tế",
190
  "semester_data": [
191
+ 0, 0, 0, 0, 16, 6, 6, 7.00, 1,
192
+ 0, 0, 0, 0, 18, 7, 7, 8.20, 1,
193
+ 0, 0, 0, 0, 17, 7, 7, 7.80, 1,
194
+ 0, 0, 0, 0, 17, 7, 6, 7.90, 1,
195
+ 0, 0, 0, 0, 19, 8, 5, 8.10, 0,
196
+ 0, 0, 8, 2, 19, 7, 6, 7.30, 1
197
  ]
198
  }
199
 
200
+ # ===== Thông tin cá nhân =====
 
 
 
 
 
 
 
 
 
 
 
201
  if sample_option == "Dùng ví dụ mẫu ngành Công nghệ thông tin":
202
+ name = st.text_input("👤 Họ tên", value=sample_cntt_example_full["name"])
203
+ student_id = st.text_input("🎓 Mã sinh viên", value=sample_cntt_example_full["student_id"])
204
+ major = st.selectbox("📚 Ngành học", ["Công nghệ thông tin", "Kinh tế"], index=0)
 
 
 
 
 
 
205
  elif sample_option == "Dùng ví dụ mẫu ngành Kinh tế":
206
+ name = st.text_input("👤 Họ tên", value=sample_kinhte_example_simple["name"])
207
+ student_id = st.text_input("🎓 Mã sinh viên", value=sample_kinhte_example_simple["student_id"])
208
+ major = st.selectbox("📚 Ngành học", ["Công nghệ thông tin", "Kinh tế"], index=1)
209
+ else:
210
+ name = st.text_input("👤 Họ tên")
211
+ student_id = st.text_input("🎓 Mã sinh viên")
212
+ major = st.selectbox("📚 Ngành học", ["Công nghệ thông tin", "Kinh tế"])
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
  st.write("---")
215
 
216
  # ===== Nhập thông tin học kỳ =====
217
  def input_semester(semester_label, default_values=None):
 
 
 
 
218
  with st.expander(f"📖 {semester_label}", expanded=True):
219
  col1, col2 = st.columns(2)
220
  with col1:
221
+ 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}")
222
+ 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}")
223
+ sotcno = st.number_input("Số tín chỉ nợ", 0, value=default_values[2] if default_values else 0, key=f"tcno_{semester_label}")
224
+ 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}")
 
225
  try:
226
+ default_tc_qua = default_values[4] - default_values[2] if default_values and len(default_values) >= 5 else 0
227
+ except:
228
+ default_tc_qua = 0
229
+ sotc_qua = st.number_input("Số tín chỉ qua môn", 0, value=default_tc_qua, key=f"tcqua_{semester_label}")
230
+ with col2:
231
+ 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}")
232
+ 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}")
233
+ mhpass = st.number_input("Số môn đạt", 0, value=default_values[6] if default_values else 0, key=f"mhpass_{semester_label}")
234
+ 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}")
235
+ 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}")
236
+ return [somon0thi, sotc0thi, sotcno, mhno, TCHK, smhk, mhpass, TBCHK, xep_loai_selected, sotc_qua]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
  def input_important_features(semester_label, default_values=None):
 
 
 
 
239
  with st.expander(f"📘 {semester_label}", expanded=True):
240
  col1, col2 = st.columns(2)
241
  with col1:
242
+ 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}")
243
+ 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}")
 
 
244
  with col2:
245
+ 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}")
246
+ return [sotc_qua, sotcno, TBCHK]
 
247
 
248
  # ===== Giao diện theo mô hình =====
249
  data = []
250
  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"]
251
 
252
+ # Mô hình 1: "Dùng toàn bộ dữ liệu"
253
  if model_type == "Dùng toàn bộ đặc trưng":
254
+ st.subheader("🔢 Nhập thông tin học kỳ chi tiết")
255
  for idx, sem in enumerate(semesters):
256
+ 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
257
+ default_values = example_data["semester_data"][idx*9:(idx+1)*9] if example_data else None
 
 
 
 
 
 
 
 
 
258
  data += input_semester(sem, default_values)
 
 
259
  nganh = 0 if major == "Công nghệ thông tin" else 1
 
260
  final_features = np.array(data + [nganh]).reshape(1, -1)
261
 
262
+ # Mô hình 2: "Dùng hình đơn giản"
263
  else:
264
+
265
+ # Ensure the example defaults to "Không ví dụ" when model type is 2
266
+
267
+ st.subheader("✨ Nhập thông tin rút gọn")
268
+ # Allow selecting an example
269
  for idx, sem in enumerate(semesters):
270
+ 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
271
+ 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)
 
 
 
 
 
 
 
 
 
272
  data += input_important_features(sem, default_values)
 
 
273
  final_features = np.array(data).reshape(1, -1)
274
 
275
  # ===== Predict =====
 
277
  if model_type == "Dùng toàn bộ đặc trưng":
278
  prediction = model_full.predict(final_features)
279
  sheet_name = "Trang tính1" # For full data model, save to Trang tính1
280
+
281
+ else:
282
  prediction = model_important.predict(final_features)
283
+ sheet_name = "Trang tính2" # For full data model, save to Trang tính1
284
+
285
 
286
  if prediction[0] == 1:
287
  st.success(f"🎉 Chúc mừng bạn {name} - {major}! Bạn có khả năng tốt nghiệp đúng hạn!")
 
290
  st.error(f"⚠️ Bạn {name} - {major} cần cố gắng hơn! Có nguy cơ trễ hạn.")
291
  st.snow()
292
 
293
+ # # Debugging: List all sheet names
294
+ # sheet_id = "1i7bDNvLVLXN93_e-FN0JLzpg1jb64Z_aEuyPjIfwbdQ" # Use your actual Spreadsheet ID
295
+ # sheet_names = list_sheet_names(sheet_id)
296
+ # st.write("Available sheet names:", sheet_names)
297
+
298
  # Ghi log lên Google Sheets
299
+ save_to_gsheet(name, student_id, major, prediction, data,sheet_name) # Pass data to save function