SarahXia0405 commited on
Commit
e8bd38b
·
verified ·
1 Parent(s): 68499d2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -299
app.py CHANGED
@@ -183,8 +183,10 @@ Currently: English & 简体中文.
183
 
184
  # ================== CSS ==================
185
  CUSTOM_CSS = """
 
186
  .header-container { padding: 10px 20px; background-color: #ffffff; border-bottom: 2px solid #f3f4f6; margin-bottom: 15px; display: flex; align-items: center; }
187
 
 
188
  .login-panel {
189
  background-color: #e5e7eb;
190
  padding: 15px;
@@ -211,6 +213,7 @@ CUSTOM_CSS = """
211
  font-weight: bold !important;
212
  }
213
 
 
214
  .main-user-guide { border: none !important; background: transparent !important; box-shadow: none !important; }
215
  .main-user-guide > .label-wrap { border: none !important; background: transparent !important; padding: 10px 0 !important; }
216
  .main-user-guide > .label-wrap span { font-size: 1.3rem !important; font-weight: 800 !important; color: #111827 !important; }
@@ -220,16 +223,24 @@ CUSTOM_CSS = """
220
  .clean-accordion > .label-wrap span { font-size: 0.9rem !important; font-weight: 500 !important; color: #374151 !important; }
221
  .clean-accordion > .label-wrap:hover { background-color: #f9fafb !important; }
222
 
 
223
  .action-btn { font-weight: bold !important; font-size: 0.9rem !important; position: relative; overflow: visible !important; }
 
 
224
 
 
225
  .html-tooltip { border-bottom: 1px dashed #999; cursor: help; position: relative; }
 
226
  .memory-line-box { border: 1px solid #e5e7eb; padding: 12px; border-radius: 8px; background-color: #f9fafb; height: 100%; display: flex; flex-direction: column; justify-content: space-between; }
227
 
 
228
  .result-box { border: 1px solid #e5e7eb; background: #ffffff; padding: 10px; border-radius: 8px; height: 100%; }
229
  .result-box .prose { font-size: 0.9rem; }
 
 
230
  """
231
 
232
- # ========== Preload Module 10 ==========
233
  MODULE10_PATH = "module10_responsible_ai.pdf"
234
  MODULE10_DOC_TYPE = "Literature Review / Paper"
235
 
@@ -254,12 +265,14 @@ else:
254
  ls_client = Client()
255
  LS_DATASET_NAME = "clare_user_events"
256
 
257
-
258
  def log_event(data: Dict):
 
 
 
259
  try:
260
  inputs = {
261
- "event_type": data.get("event_type"),
262
  "question": data.get("question"),
 
263
  "student_id": data.get("student_id"),
264
  }
265
  outputs = {
@@ -280,8 +293,7 @@ def log_event(data: Dict):
280
  except Exception as e:
281
  print("LangSmith log failed:", e)
282
 
283
-
284
- # ===== Reference helper =====
285
  def format_references(
286
  rag_chunks: List[Dict], max_files: int = 2, max_sections_per_file: int = 3
287
  ) -> str:
@@ -314,7 +326,6 @@ def format_references(
314
  return ""
315
  return "\n".join(lines)
316
 
317
-
318
  def is_academic_query(message: str) -> bool:
319
  if not message:
320
  return False
@@ -330,7 +341,7 @@ def is_academic_query(message: str) -> bool:
330
  "thanks", "thank", "thank you",
331
  "ok", "okay",
332
  "bye", "goodbye", "see you",
333
- "haha", "lol",
334
  }
335
  tokens = m.split()
336
 
@@ -361,20 +372,56 @@ def is_academic_query(message: str) -> bool:
361
 
362
  return True
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
  # ================== Gradio App ==================
366
  with gr.Blocks(
367
  title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
368
  ) as demo:
369
 
 
370
  course_outline_state = gr.State(preloaded_topics or DEFAULT_COURSE_TOPICS)
371
  weakness_state = gr.State([])
372
  cognitive_state_state = gr.State({"confusion": 0, "mastery": 0})
373
  rag_chunks_state = gr.State(preloaded_chunks or [])
374
 
375
- last_question_state = gr.State("")
376
- last_answer_state = gr.State("")
377
-
378
  user_name_state = gr.State("")
379
  user_id_state = gr.State("")
380
 
@@ -429,6 +476,7 @@ with gr.Blocks(
429
  interactive=False,
430
  )
431
 
 
432
  with gr.Accordion(
433
  "User Guide", open=True, elem_classes="main-user-guide"
434
  ):
@@ -518,39 +566,17 @@ with gr.Blocks(
518
  height=450,
519
  avatar_images=(None, CLARE_LOGO_PATH),
520
  show_label=False,
521
- bubble_full_width=False,
522
  type="tuples",
523
  )
524
 
525
- gr.Markdown("#### Rate Clare’s last answer")
526
- with gr.Row():
527
- thumb_up_btn = gr.Button(
528
- "👍 Helpful", size="sm", interactive=False
529
- )
530
- thumb_down_btn = gr.Button(
531
- "👎 Not helpful", size="sm", interactive=False
532
- )
533
-
534
- feedback_toggle_btn = gr.Button(
535
- "Give detailed feedback",
536
- size="sm",
537
- variant="secondary",
538
- interactive=False,
539
- )
540
- feedback_text = gr.Textbox(
541
- label="What worked well or what was wrong?",
542
- placeholder="Optional: describe what you liked / what was confusing or incorrect.",
543
- lines=3,
544
- visible=False,
545
- )
546
- feedback_submit_btn = gr.Button(
547
- "Submit Feedback",
548
- size="sm",
549
- variant="primary",
550
- visible=False,
551
- interactive=False,
552
  )
553
 
 
554
  user_input = gr.Textbox(
555
  label="Your Input",
556
  placeholder="Please log in on the right before asking Clare anything...",
@@ -560,6 +586,7 @@ with gr.Blocks(
560
  interactive=False,
561
  )
562
 
 
563
  with gr.Row():
564
  with gr.Column(scale=2):
565
  syllabus_file = gr.File(
@@ -690,11 +717,6 @@ with gr.Blocks(
690
  learning_mode: gr.update(interactive=False),
691
  model_name: gr.update(interactive=False),
692
  docs_btn: gr.update(interactive=False),
693
- thumb_up_btn: gr.update(interactive=False),
694
- thumb_down_btn: gr.update(interactive=False),
695
- feedback_toggle_btn: gr.update(interactive=False),
696
- feedback_text: gr.update(visible=False, value=""),
697
- feedback_submit_btn: gr.update(interactive=False, visible=False),
698
  }
699
 
700
  info_html = f"""
@@ -725,15 +747,6 @@ with gr.Blocks(
725
  learning_mode: gr.update(interactive=True),
726
  model_name: gr.update(interactive=False),
727
  docs_btn: gr.update(interactive=True),
728
- thumb_up_btn: gr.update(
729
- interactive=True, value="👍 Helpful", variant="secondary"
730
- ),
731
- thumb_down_btn: gr.update(
732
- interactive=True, value="👎 Not helpful", variant="secondary"
733
- ),
734
- feedback_toggle_btn: gr.update(interactive=True),
735
- feedback_text: gr.update(visible=False, value=""),
736
- feedback_submit_btn: gr.update(interactive=True, visible=False),
737
  }
738
 
739
  login_confirm_btn.click(
@@ -758,11 +771,6 @@ with gr.Blocks(
758
  learning_mode,
759
  model_name,
760
  docs_btn,
761
- thumb_up_btn,
762
- thumb_down_btn,
763
- feedback_toggle_btn,
764
- feedback_text,
765
- feedback_submit_btn,
766
  ],
767
  )
768
 
@@ -791,11 +799,6 @@ with gr.Blocks(
791
  language_preference: gr.update(interactive=False),
792
  learning_mode: gr.update(interactive=False),
793
  docs_btn: gr.update(interactive=False),
794
- thumb_up_btn: gr.update(interactive=False),
795
- thumb_down_btn: gr.update(interactive=False),
796
- feedback_toggle_btn: gr.update(interactive=False),
797
- feedback_text: gr.update(visible=False, value=""),
798
- feedback_submit_btn: gr.update(interactive=False, visible=False),
799
  }
800
 
801
  logout_btn.click(
@@ -820,11 +823,6 @@ with gr.Blocks(
820
  language_preference,
821
  learning_mode,
822
  docs_btn,
823
- thumb_up_btn,
824
- thumb_down_btn,
825
- feedback_toggle_btn,
826
- feedback_text,
827
- feedback_submit_btn,
828
  ],
829
  )
830
 
@@ -886,14 +884,6 @@ with gr.Blocks(
886
  doc_type_val,
887
  user_id_val,
888
  ):
889
- # 没登录
890
- default_up = gr.update(
891
- value="👍 Helpful", variant="secondary", interactive=False
892
- )
893
- default_down = gr.update(
894
- value="👎 Not helpful", variant="secondary", interactive=False
895
- )
896
-
897
  if not user_id_val:
898
  out_msg = (
899
  "🔒 Please log in with your Student Name and Email/ID on the right "
@@ -905,17 +895,7 @@ with gr.Blocks(
905
  weaknesses or [],
906
  cognitive_state or {"confusion": 0, "mastery": 0},
907
  )
908
- return (
909
- "",
910
- new_history,
911
- weaknesses,
912
- cognitive_state,
913
- new_status,
914
- "",
915
- "",
916
- default_up,
917
- default_down,
918
- )
919
 
920
  resolved_lang = detect_language(message or "", lang_pref)
921
 
@@ -925,24 +905,7 @@ with gr.Blocks(
925
  weaknesses or [],
926
  cognitive_state or {"confusion": 0, "mastery": 0},
927
  )
928
- # 已登录时,允许评分,所以按钮可点
929
- logged_up = gr.update(
930
- value="👍 Helpful", variant="secondary", interactive=True
931
- )
932
- logged_down = gr.update(
933
- value="👎 Not helpful", variant="secondary", interactive=True
934
- )
935
- return (
936
- "",
937
- chat_history,
938
- weaknesses,
939
- cognitive_state,
940
- new_status,
941
- "",
942
- "",
943
- logged_up,
944
- logged_down,
945
- )
946
 
947
  weaknesses = update_weaknesses_from_message(message, weaknesses or [])
948
  cognitive_state = update_cognitive_state_from_message(message, cognitive_state)
@@ -1004,25 +967,7 @@ with gr.Blocks(
1004
 
1005
  new_status = render_session_status(mode_val, weaknesses, cognitive_state)
1006
 
1007
- # 新一轮回答出来 -> 重置按钮为默认可点状态
1008
- logged_up = gr.update(
1009
- value="👍 Helpful", variant="secondary", interactive=True
1010
- )
1011
- logged_down = gr.update(
1012
- value="👎 Not helpful", variant="secondary", interactive=True
1013
- )
1014
-
1015
- return (
1016
- "",
1017
- new_history,
1018
- weaknesses,
1019
- cognitive_state,
1020
- new_status,
1021
- message,
1022
- answer,
1023
- logged_up,
1024
- logged_down,
1025
- )
1026
 
1027
  user_input.submit(
1028
  respond,
@@ -1045,10 +990,6 @@ with gr.Blocks(
1045
  weakness_state,
1046
  cognitive_state_state,
1047
  session_status,
1048
- last_question_state,
1049
- last_answer_state,
1050
- thumb_up_btn,
1051
- thumb_down_btn,
1052
  ],
1053
  )
1054
 
@@ -1168,162 +1109,6 @@ with gr.Blocks(
1168
  [chatbot, weakness_state, cognitive_state_state, session_status],
1169
  )
1170
 
1171
- # ===== Feedback Handlers =====
1172
- def show_feedback_box():
1173
- return {
1174
- feedback_text: gr.update(visible=True),
1175
- feedback_submit_btn: gr.update(visible=True),
1176
- }
1177
-
1178
- feedback_toggle_btn.click(
1179
- show_feedback_box,
1180
- None,
1181
- [feedback_text, feedback_submit_btn],
1182
- )
1183
-
1184
- def send_thumb_up(last_q, last_a, user_id_val, mode_val, model_name_val, lang_pref):
1185
- if not last_q and not last_a:
1186
- print("No last QA to log for thumbs_up.")
1187
- # 仍然返回按钮状态,防止 Gradio 报错
1188
- return (
1189
- gr.update(value="👍 Helpful", variant="secondary"),
1190
- gr.update(value="👎 Not helpful", variant="secondary"),
1191
- )
1192
- try:
1193
- log_event(
1194
- {
1195
- "experiment_id": "RESP_AI_W10",
1196
- "student_id": user_id_val or "ANON",
1197
- "event_type": "thumbs_up",
1198
- "timestamp": time.time(),
1199
- "question": last_q,
1200
- "answer": last_a,
1201
- "model_name": model_name_val,
1202
- "language": lang_pref,
1203
- "learning_mode": mode_val,
1204
- }
1205
- )
1206
- print("[Feedback] thumbs_up logged to LangSmith.")
1207
- except Exception as e:
1208
- print("thumb_up log error:", e)
1209
-
1210
- # 实时视觉反馈:左边按钮高亮 + 标记 sent,右边保持可点普通状态
1211
- return (
1212
- gr.update(
1213
- value="👍 Helpful (sent)", variant="primary", interactive=True
1214
- ),
1215
- gr.update(value="👎 Not helpful", variant="secondary", interactive=True),
1216
- )
1217
-
1218
- def send_thumb_down(
1219
- last_q, last_a, user_id_val, mode_val, model_name_val, lang_pref
1220
- ):
1221
- if not last_q and not last_a:
1222
- print("No last QA to log for thumbs_down.")
1223
- return (
1224
- gr.update(value="👍 Helpful", variant="secondary"),
1225
- gr.update(value="👎 Not helpful", variant="secondary"),
1226
- )
1227
- try:
1228
- log_event(
1229
- {
1230
- "experiment_id": "RESP_AI_W10",
1231
- "student_id": user_id_val or "ANON",
1232
- "event_type": "thumbs_down",
1233
- "timestamp": time.time(),
1234
- "question": last_q,
1235
- "answer": last_a,
1236
- "model_name": model_name_val,
1237
- "language": lang_pref,
1238
- "learning_mode": mode_val,
1239
- }
1240
- )
1241
- print("[Feedback] thumbs_down logged to LangSmith.")
1242
- except Exception as e:
1243
- print("thumb_down log error:", e)
1244
-
1245
- return (
1246
- gr.update(value="👍 Helpful", variant="secondary", interactive=True),
1247
- gr.update(
1248
- value="👎 Not helpful (sent)",
1249
- variant="primary",
1250
- interactive=True,
1251
- ),
1252
- )
1253
-
1254
- thumb_up_btn.click(
1255
- send_thumb_up,
1256
- [
1257
- last_question_state,
1258
- last_answer_state,
1259
- user_id_state,
1260
- learning_mode,
1261
- model_name,
1262
- language_preference,
1263
- ],
1264
- [thumb_up_btn, thumb_down_btn],
1265
- )
1266
-
1267
- thumb_down_btn.click(
1268
- send_thumb_down,
1269
- [
1270
- last_question_state,
1271
- last_answer_state,
1272
- user_id_state,
1273
- learning_mode,
1274
- model_name,
1275
- language_preference,
1276
- ],
1277
- [thumb_up_btn, thumb_down_btn],
1278
- )
1279
-
1280
- def submit_detailed_feedback(
1281
- text, last_q, last_a, user_id_val, mode_val, model_name_val, lang_pref
1282
- ):
1283
- if not text or not text.strip():
1284
- return gr.update(
1285
- value="",
1286
- placeholder="Please enter some feedback before submitting.",
1287
- )
1288
-
1289
- try:
1290
- log_event(
1291
- {
1292
- "experiment_id": "RESP_AI_W10",
1293
- "student_id": user_id_val or "ANON",
1294
- "event_type": "detailed_feedback",
1295
- "timestamp": time.time(),
1296
- "question": last_q,
1297
- "answer": last_a,
1298
- "feedback_text": text.strip(),
1299
- "model_name": model_name_val,
1300
- "language": lang_pref,
1301
- "learning_mode": mode_val,
1302
- }
1303
- )
1304
- print("[Feedback] detailed_feedback logged to LangSmith.")
1305
- except Exception as e:
1306
- print("detailed_feedback log error:", e)
1307
-
1308
- return gr.update(
1309
- value="",
1310
- placeholder="Thanks! Your feedback has been recorded.",
1311
- )
1312
-
1313
- feedback_submit_btn.click(
1314
- submit_detailed_feedback,
1315
- [
1316
- feedback_text,
1317
- last_question_state,
1318
- last_answer_state,
1319
- user_id_state,
1320
- learning_mode,
1321
- model_name,
1322
- language_preference,
1323
- ],
1324
- [feedback_text],
1325
- )
1326
-
1327
  # ===== Export / Summary =====
1328
  export_btn.click(
1329
  lambda h, c, m, w, cog: export_conversation(h, c, m, w, cog),
@@ -1350,18 +1135,7 @@ with gr.Blocks(
1350
  def clear_all():
1351
  empty_state = {"confusion": 0, "mastery": 0}
1352
  default_status = render_session_status("Concept Explainer", [], empty_state)
1353
- return (
1354
- [],
1355
- [],
1356
- empty_state,
1357
- [],
1358
- "",
1359
- default_status,
1360
- "",
1361
- "",
1362
- gr.update(value="👍 Helpful", variant="secondary", interactive=False),
1363
- gr.update(value="👎 Not helpful", variant="secondary", interactive=False),
1364
- )
1365
 
1366
  clear_btn.click(
1367
  clear_all,
@@ -1373,10 +1147,6 @@ with gr.Blocks(
1373
  rag_chunks_state,
1374
  result_display,
1375
  session_status,
1376
- last_question_state,
1377
- last_answer_state,
1378
- thumb_up_btn,
1379
- thumb_down_btn,
1380
  ],
1381
  queue=False,
1382
  )
 
183
 
184
  # ================== CSS ==================
185
  CUSTOM_CSS = """
186
+ /* --- Main Header --- */
187
  .header-container { padding: 10px 20px; background-color: #ffffff; border-bottom: 2px solid #f3f4f6; margin-bottom: 15px; display: flex; align-items: center; }
188
 
189
+ /* --- Sidebar Login Panel --- */
190
  .login-panel {
191
  background-color: #e5e7eb;
192
  padding: 15px;
 
213
  font-weight: bold !important;
214
  }
215
 
216
+ /* User Guide */
217
  .main-user-guide { border: none !important; background: transparent !important; box-shadow: none !important; }
218
  .main-user-guide > .label-wrap { border: none !important; background: transparent !important; padding: 10px 0 !important; }
219
  .main-user-guide > .label-wrap span { font-size: 1.3rem !important; font-weight: 800 !important; color: #111827 !important; }
 
223
  .clean-accordion > .label-wrap span { font-size: 0.9rem !important; font-weight: 500 !important; color: #374151 !important; }
224
  .clean-accordion > .label-wrap:hover { background-color: #f9fafb !important; }
225
 
226
+ /* Action Buttons */
227
  .action-btn { font-weight: bold !important; font-size: 0.9rem !important; position: relative; overflow: visible !important; }
228
+ .action-btn:hover::before { content: "See User Guide for details"; position: absolute; bottom: 110%; left: 50%; transform: translateX(-50%); background-color: #333; color: #fff; padding: 5px 10px; border-radius: 5px; font-size: 12px; white-space: nowrap; z-index: 1000; pointer-events: none; opacity: 0; animation: fadeIn 0.2s forwards; }
229
+ .action-btn:hover::after { content: ""; position: absolute; bottom: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: #333 transparent transparent transparent; opacity: 0; animation: fadeIn 0.2s forwards; }
230
 
231
+ /* Tooltips & Memory Line */
232
  .html-tooltip { border-bottom: 1px dashed #999; cursor: help; position: relative; }
233
+ .html-tooltip:hover::before { content: attr(data-tooltip); position: absolute; bottom: 120%; left: 0; background-color: #333; color: #fff; padding: 5px 8px; border-radius: 4px; font-size: 11px; white-space: nowrap; z-index: 100; pointer-events: none; }
234
  .memory-line-box { border: 1px solid #e5e7eb; padding: 12px; border-radius: 8px; background-color: #f9fafb; height: 100%; display: flex; flex-direction: column; justify-content: space-between; }
235
 
236
+ /* Results Box Style */
237
  .result-box { border: 1px solid #e5e7eb; background: #ffffff; padding: 10px; border-radius: 8px; height: 100%; }
238
  .result-box .prose { font-size: 0.9rem; }
239
+
240
+ @keyframes fadeIn { to { opacity: 1; } }
241
  """
242
 
243
+ # ========== Preload Module 10 PDF ==========
244
  MODULE10_PATH = "module10_responsible_ai.pdf"
245
  MODULE10_DOC_TYPE = "Literature Review / Paper"
246
 
 
265
  ls_client = Client()
266
  LS_DATASET_NAME = "clare_user_events"
267
 
 
268
  def log_event(data: Dict):
269
+ """
270
+ 所有事件(chat_turn / micro_quiz_start / like / dislike)统一写入 LangSmith Dataset。
271
+ """
272
  try:
273
  inputs = {
 
274
  "question": data.get("question"),
275
+ "event_type": data.get("event_type"),
276
  "student_id": data.get("student_id"),
277
  }
278
  outputs = {
 
293
  except Exception as e:
294
  print("LangSmith log failed:", e)
295
 
296
+ # ===== Reference Formatting Helper =====
 
297
  def format_references(
298
  rag_chunks: List[Dict], max_files: int = 2, max_sections_per_file: int = 3
299
  ) -> str:
 
326
  return ""
327
  return "\n".join(lines)
328
 
 
329
  def is_academic_query(message: str) -> bool:
330
  if not message:
331
  return False
 
341
  "thanks", "thank", "thank you",
342
  "ok", "okay",
343
  "bye", "goodbye", "see you",
344
+ "haha", "lol"
345
  }
346
  tokens = m.split()
347
 
 
372
 
373
  return True
374
 
375
+ # ======= Chatbot like/dislike handler (per-message, ChatGPT-style) =======
376
+ def handle_like(data: gr.LikeData,
377
+ history,
378
+ user_id_val,
379
+ mode_val,
380
+ model_name_val,
381
+ lang_pref):
382
+ """
383
+ data.index: 第几条消息被点
384
+ data.value: "like" / "dislike"
385
+ history: 当前 Chatbot 的 [ [user, assistant], ... ]
386
+ """
387
+ try:
388
+ idx = data.index
389
+ value = data.value # "like" or "dislike"
390
+ if history is None or idx < 0 or idx >= len(history):
391
+ print("[Like] invalid index", idx)
392
+ return
393
+
394
+ question, answer = history[idx]
395
+ student_id = user_id_val or "ANON"
396
+
397
+ log_event(
398
+ {
399
+ "experiment_id": "RESP_AI_W10",
400
+ "student_id": student_id,
401
+ "event_type": value, # "like" / "dislike"
402
+ "timestamp": time.time(),
403
+ "question": question,
404
+ "answer": answer,
405
+ "model_name": model_name_val,
406
+ "language": lang_pref,
407
+ "learning_mode": mode_val,
408
+ }
409
+ )
410
+ print(f"[Like] event logged: index={idx}, value={value}")
411
+ except Exception as e:
412
+ print("handle_like error:", e)
413
 
414
  # ================== Gradio App ==================
415
  with gr.Blocks(
416
  title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
417
  ) as demo:
418
 
419
+ # 全局状态
420
  course_outline_state = gr.State(preloaded_topics or DEFAULT_COURSE_TOPICS)
421
  weakness_state = gr.State([])
422
  cognitive_state_state = gr.State({"confusion": 0, "mastery": 0})
423
  rag_chunks_state = gr.State(preloaded_chunks or [])
424
 
 
 
 
425
  user_name_state = gr.State("")
426
  user_id_state = gr.State("")
427
 
 
476
  interactive=False,
477
  )
478
 
479
+ # User Guide
480
  with gr.Accordion(
481
  "User Guide", open=True, elem_classes="main-user-guide"
482
  ):
 
566
  height=450,
567
  avatar_images=(None, CLARE_LOGO_PATH),
568
  show_label=False,
 
569
  type="tuples",
570
  )
571
 
572
+ # ChatGPT-style per-message like/dislike
573
+ chatbot.like(
574
+ fn=handle_like,
575
+ inputs=[chatbot, user_id_state, learning_mode, model_name, language_preference],
576
+ outputs=[],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
577
  )
578
 
579
+ # 用户输入
580
  user_input = gr.Textbox(
581
  label="Your Input",
582
  placeholder="Please log in on the right before asking Clare anything...",
 
586
  interactive=False,
587
  )
588
 
589
+ # Upload / File type / Memory Line
590
  with gr.Row():
591
  with gr.Column(scale=2):
592
  syllabus_file = gr.File(
 
717
  learning_mode: gr.update(interactive=False),
718
  model_name: gr.update(interactive=False),
719
  docs_btn: gr.update(interactive=False),
 
 
 
 
 
720
  }
721
 
722
  info_html = f"""
 
747
  learning_mode: gr.update(interactive=True),
748
  model_name: gr.update(interactive=False),
749
  docs_btn: gr.update(interactive=True),
 
 
 
 
 
 
 
 
 
750
  }
751
 
752
  login_confirm_btn.click(
 
771
  learning_mode,
772
  model_name,
773
  docs_btn,
 
 
 
 
 
774
  ],
775
  )
776
 
 
799
  language_preference: gr.update(interactive=False),
800
  learning_mode: gr.update(interactive=False),
801
  docs_btn: gr.update(interactive=False),
 
 
 
 
 
802
  }
803
 
804
  logout_btn.click(
 
823
  language_preference,
824
  learning_mode,
825
  docs_btn,
 
 
 
 
 
826
  ],
827
  )
828
 
 
884
  doc_type_val,
885
  user_id_val,
886
  ):
 
 
 
 
 
 
 
 
887
  if not user_id_val:
888
  out_msg = (
889
  "🔒 Please log in with your Student Name and Email/ID on the right "
 
895
  weaknesses or [],
896
  cognitive_state or {"confusion": 0, "mastery": 0},
897
  )
898
+ return "", new_history, weaknesses, cognitive_state, new_status
 
 
 
 
 
 
 
 
 
 
899
 
900
  resolved_lang = detect_language(message or "", lang_pref)
901
 
 
905
  weaknesses or [],
906
  cognitive_state or {"confusion": 0, "mastery": 0},
907
  )
908
+ return "", chat_history, weaknesses, cognitive_state, new_status
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
909
 
910
  weaknesses = update_weaknesses_from_message(message, weaknesses or [])
911
  cognitive_state = update_cognitive_state_from_message(message, cognitive_state)
 
967
 
968
  new_status = render_session_status(mode_val, weaknesses, cognitive_state)
969
 
970
+ return "", new_history, weaknesses, cognitive_state, new_status
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
971
 
972
  user_input.submit(
973
  respond,
 
990
  weakness_state,
991
  cognitive_state_state,
992
  session_status,
 
 
 
 
993
  ],
994
  )
995
 
 
1109
  [chatbot, weakness_state, cognitive_state_state, session_status],
1110
  )
1111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1112
  # ===== Export / Summary =====
1113
  export_btn.click(
1114
  lambda h, c, m, w, cog: export_conversation(h, c, m, w, cog),
 
1135
  def clear_all():
1136
  empty_state = {"confusion": 0, "mastery": 0}
1137
  default_status = render_session_status("Concept Explainer", [], empty_state)
1138
+ return [], [], empty_state, [], "", default_status
 
 
 
 
 
 
 
 
 
 
 
1139
 
1140
  clear_btn.click(
1141
  clear_all,
 
1147
  rag_chunks_state,
1148
  result_display,
1149
  session_status,
 
 
 
 
1150
  ],
1151
  queue=False,
1152
  )