SarahXia0405 commited on
Commit
403eeeb
·
verified ·
1 Parent(s): 34ec5a2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -15
app.py CHANGED
@@ -50,6 +50,7 @@ def image_to_base64(image_path: str) -> str:
50
  mime = "image/png"
51
  return f"data:{mime};base64,{encoded_string}"
52
 
 
53
  # ================== User Guide Content ==================
54
  USER_GUIDE_SECTIONS = {
55
  "getting_started": """
@@ -389,6 +390,9 @@ with gr.Blocks(
389
  # ✅ 当前“最近一次回答”是否已经被点赞/点踩(只允许一次)
390
  feedback_used_state = gr.State(False)
391
 
 
 
 
392
  # --- Header ---
393
  with gr.Row(elem_classes="header-container"):
394
  with gr.Column(scale=3):
@@ -532,6 +536,9 @@ with gr.Blocks(
532
  type="tuples",
533
  )
534
 
 
 
 
535
  # Rating bar (last answer)
536
  gr.Markdown("#### Rate Clare’s last answer")
537
  with gr.Row():
@@ -701,6 +708,8 @@ with gr.Blocks(
701
  feedback_toggle_btn: gr.update(interactive=False),
702
  feedback_text: gr.update(visible=False, value=""),
703
  feedback_submit_btn: gr.update(interactive=False, visible=False),
 
 
704
  }
705
 
706
  info_html = f"""
@@ -738,6 +747,8 @@ with gr.Blocks(
738
  feedback_toggle_btn: gr.update(interactive=True),
739
  feedback_text: gr.update(visible=False, value=""),
740
  feedback_submit_btn: gr.update(interactive=True, visible=False),
 
 
741
  }
742
 
743
  login_confirm_btn.click(
@@ -768,6 +779,8 @@ with gr.Blocks(
768
  feedback_toggle_btn,
769
  feedback_text,
770
  feedback_submit_btn,
 
 
771
  ],
772
  )
773
 
@@ -802,6 +815,8 @@ with gr.Blocks(
802
  feedback_toggle_btn: gr.update(interactive=False),
803
  feedback_text: gr.update(visible=False, value=""),
804
  feedback_submit_btn: gr.update(interactive=False, visible=False),
 
 
805
  }
806
 
807
  logout_btn.click(
@@ -832,6 +847,8 @@ with gr.Blocks(
832
  feedback_toggle_btn,
833
  feedback_text,
834
  feedback_submit_btn,
 
 
835
  ],
836
  )
837
 
@@ -895,6 +912,14 @@ with gr.Blocks(
895
  user_id_val,
896
  feedback_used,
897
  ):
 
 
 
 
 
 
 
 
898
  # 未登录:不解锁按钮
899
  if not user_id_val:
900
  out_msg = (
@@ -907,6 +932,7 @@ with gr.Blocks(
907
  weaknesses or [],
908
  cognitive_state or {"confusion": 0, "mastery": 0},
909
  )
 
910
  return (
911
  "",
912
  new_history,
@@ -918,9 +944,14 @@ with gr.Blocks(
918
  feedback_used,
919
  gr.update(interactive=False, value="👍 Helpful"),
920
  gr.update(interactive=False, value="👎 Not helpful"),
 
 
921
  )
922
 
 
923
  resolved_lang = detect_language(message or "", lang_pref)
 
 
924
 
925
  # 空输入:不改变按钮状态
926
  if not message or not message.strip():
@@ -929,6 +960,7 @@ with gr.Blocks(
929
  weaknesses or [],
930
  cognitive_state or {"confusion": 0, "mastery": 0},
931
  )
 
932
  return (
933
  "",
934
  chat_history,
@@ -940,20 +972,35 @@ with gr.Blocks(
940
  feedback_used,
941
  gr.update(),
942
  gr.update(),
 
 
943
  )
944
 
 
 
945
  weaknesses = update_weaknesses_from_message(message, weaknesses or [])
 
 
 
 
946
  cognitive_state = update_cognitive_state_from_message(message, cognitive_state)
 
 
947
 
 
 
948
  if is_academic_query(message):
949
  rag_context_text, rag_used_chunks = retrieve_relevant_chunks(
950
  message, rag_chunks or []
951
  )
952
  else:
953
  rag_context_text, rag_used_chunks = "", []
 
 
954
 
955
- start_ts = time.time()
956
- answer, new_history = chat_with_clare(
 
957
  message=message,
958
  history=chat_history,
959
  model_name=model_name_val,
@@ -965,9 +1012,31 @@ with gr.Blocks(
965
  cognitive_state=cognitive_state,
966
  rag_context=rag_context_text,
967
  )
968
- end_ts = time.time()
969
- latency_ms = (end_ts - start_ts) * 1000.0
 
 
 
 
 
 
 
970
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
971
  if is_academic_query(message) and rag_used_chunks:
972
  ref_text = format_references(rag_used_chunks)
973
  else:
@@ -980,6 +1049,7 @@ with gr.Blocks(
980
  new_history[-1] = [last_user, last_assistant]
981
  answer = last_assistant
982
 
 
983
  student_id = user_id_val or "ANON"
984
  experiment_id = "RESP_AI_W10"
985
  try:
@@ -988,13 +1058,18 @@ with gr.Blocks(
988
  "experiment_id": experiment_id,
989
  "student_id": student_id,
990
  "event_type": "chat_turn",
991
- "timestamp": end_ts,
992
- "latency_ms": latency_ms,
993
  "question": message,
994
  "answer": answer,
995
  "model_name": model_name_val,
996
  "language": resolved_lang,
997
  "learning_mode": mode_val,
 
 
 
 
 
998
  }
999
  )
1000
  except Exception as e:
@@ -1014,6 +1089,8 @@ with gr.Blocks(
1014
  False,
1015
  gr.update(interactive=True, value="👍 Helpful"),
1016
  gr.update(interactive=True, value="👎 Not helpful"),
 
 
1017
  )
1018
 
1019
  user_input.submit(
@@ -1043,6 +1120,8 @@ with gr.Blocks(
1043
  feedback_used_state,
1044
  thumb_up_btn,
1045
  thumb_down_btn,
 
 
1046
  ],
1047
  )
1048
 
@@ -1059,8 +1138,16 @@ with gr.Blocks(
1059
  doc_type_val,
1060
  user_id_val,
1061
  ):
 
 
 
 
 
 
 
1062
  if not user_id_val:
1063
  gr.Info("Please log in first to start a micro-quiz.", title="Login required")
 
1064
  return (
1065
  chat_history,
1066
  weaknesses,
@@ -1070,6 +1157,8 @@ with gr.Blocks(
1070
  weaknesses or [],
1071
  cognitive_state or {"confusion": 0, "mastery": 0},
1072
  ),
 
 
1073
  )
1074
 
1075
  quiz_instruction = (
@@ -1100,13 +1189,18 @@ with gr.Blocks(
1100
  )
1101
 
1102
  resolved_lang = lang_pref
 
 
1103
 
1104
- start_ts = time.time()
1105
  quiz_ctx_text, _quiz_ctx_chunks = retrieve_relevant_chunks(
1106
  "Module 10 quiz", rag_chunks or []
1107
  )
 
 
1108
 
1109
- answer, new_history = chat_with_clare(
 
1110
  message=quiz_instruction,
1111
  history=chat_history,
1112
  model_name=model_name_val,
@@ -1118,32 +1212,49 @@ with gr.Blocks(
1118
  cognitive_state=cognitive_state,
1119
  rag_context=quiz_ctx_text,
1120
  )
1121
- end_ts = time.time()
1122
- latency_ms = (end_ts - start_ts) * 1000.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1123
 
1124
  student_id = user_id_val or "ANON"
1125
  experiment_id = "RESP_AI_W10"
1126
-
1127
  try:
1128
  log_event(
1129
  {
1130
  "experiment_id": experiment_id,
1131
  "student_id": student_id,
1132
  "event_type": "micro_quiz_start",
1133
- "timestamp": end_ts,
1134
- "latency_ms": latency_ms,
1135
  "question": quiz_instruction,
1136
  "answer": answer,
1137
  "model_name": model_name_val,
1138
  "language": resolved_lang,
1139
  "learning_mode": mode_val,
 
1140
  }
1141
  )
1142
  except Exception as e:
1143
  print("log_event error:", e)
1144
 
1145
  new_status = render_session_status(mode_val, weaknesses, cognitive_state)
1146
- return new_history, weaknesses, cognitive_state, new_status
1147
 
1148
  quiz_btn.click(
1149
  start_micro_quiz,
@@ -1159,7 +1270,7 @@ with gr.Blocks(
1159
  doc_type,
1160
  user_id_state,
1161
  ],
1162
- [chatbot, weakness_state, cognitive_state_state, session_status],
1163
  )
1164
 
1165
  # ===== Feedback Handlers (thumb + detailed) =====
@@ -1389,6 +1500,8 @@ with gr.Blocks(
1389
  False,
1390
  gr.update(interactive=False, value="👍 Helpful"),
1391
  gr.update(interactive=False, value="👎 Not helpful"),
 
 
1392
  )
1393
 
1394
  clear_btn.click(
@@ -1406,6 +1519,8 @@ with gr.Blocks(
1406
  feedback_used_state,
1407
  thumb_up_btn,
1408
  thumb_down_btn,
 
 
1409
  ],
1410
  queue=False,
1411
  )
 
50
  mime = "image/png"
51
  return f"data:{mime};base64,{encoded_string}"
52
 
53
+
54
  # ================== User Guide Content ==================
55
  USER_GUIDE_SECTIONS = {
56
  "getting_started": """
 
390
  # ✅ 当前“最近一次回答”是否已经被点赞/点踩(只允许一次)
391
  feedback_used_state = gr.State(False)
392
 
393
+ # ✅ 性能输出
394
+ perf_state = gr.State({})
395
+
396
  # --- Header ---
397
  with gr.Row(elem_classes="header-container"):
398
  with gr.Column(scale=3):
 
536
  type="tuples",
537
  )
538
 
539
+ # ✅ profiling output JSON (shows your TTFT / tokens/sec etc.)
540
+ perf_output = gr.JSON(label="Output", value={})
541
+
542
  # Rating bar (last answer)
543
  gr.Markdown("#### Rate Clare’s last answer")
544
  with gr.Row():
 
708
  feedback_toggle_btn: gr.update(interactive=False),
709
  feedback_text: gr.update(visible=False, value=""),
710
  feedback_submit_btn: gr.update(interactive=False, visible=False),
711
+ perf_state: {}, # ✅
712
+ perf_output: gr.update(value={}), # ✅
713
  }
714
 
715
  info_html = f"""
 
747
  feedback_toggle_btn: gr.update(interactive=True),
748
  feedback_text: gr.update(visible=False, value=""),
749
  feedback_submit_btn: gr.update(interactive=True, visible=False),
750
+ perf_state: {}, # ✅
751
+ perf_output: gr.update(value={}), # ✅
752
  }
753
 
754
  login_confirm_btn.click(
 
779
  feedback_toggle_btn,
780
  feedback_text,
781
  feedback_submit_btn,
782
+ perf_state, # ✅
783
+ perf_output, # ✅
784
  ],
785
  )
786
 
 
815
  feedback_toggle_btn: gr.update(interactive=False),
816
  feedback_text: gr.update(visible=False, value=""),
817
  feedback_submit_btn: gr.update(interactive=False, visible=False),
818
+ perf_state: {}, # ✅
819
+ perf_output: gr.update(value={}), # ✅
820
  }
821
 
822
  logout_btn.click(
 
847
  feedback_toggle_btn,
848
  feedback_text,
849
  feedback_submit_btn,
850
+ perf_state, # ✅
851
+ perf_output, # ✅
852
  ],
853
  )
854
 
 
912
  user_id_val,
913
  feedback_used,
914
  ):
915
+ # perf container
916
+ t0 = time.perf_counter()
917
+ marks = {"start": 0}
918
+ segs = {}
919
+
920
+ def mark(name: str):
921
+ marks[name] = (time.perf_counter() - t0) * 1000.0
922
+
923
  # 未登录:不解锁按钮
924
  if not user_id_val:
925
  out_msg = (
 
932
  weaknesses or [],
933
  cognitive_state or {"confusion": 0, "mastery": 0},
934
  )
935
+ perf = {"marks_ms": marks, "segments_ms": segs, "total_ms": (time.perf_counter() - t0) * 1000.0}
936
  return (
937
  "",
938
  new_history,
 
944
  feedback_used,
945
  gr.update(interactive=False, value="👍 Helpful"),
946
  gr.update(interactive=False, value="👎 Not helpful"),
947
+ perf, # ✅ perf_state
948
+ perf, # ✅ perf_output
949
  )
950
 
951
+ # language detect
952
  resolved_lang = detect_language(message or "", lang_pref)
953
+ mark("language_detect_done")
954
+ segs["language_detect_done"] = marks["language_detect_done"] - marks["start"]
955
 
956
  # 空输入:不改变按钮状态
957
  if not message or not message.strip():
 
960
  weaknesses or [],
961
  cognitive_state or {"confusion": 0, "mastery": 0},
962
  )
963
+ perf = {"marks_ms": marks, "segments_ms": segs, "total_ms": (time.perf_counter() - t0) * 1000.0}
964
  return (
965
  "",
966
  chat_history,
 
972
  feedback_used,
973
  gr.update(),
974
  gr.update(),
975
+ perf, # ✅
976
+ perf, # ✅
977
  )
978
 
979
+ # weakness/cognitive updates
980
+ t_w0 = time.perf_counter()
981
  weaknesses = update_weaknesses_from_message(message, weaknesses or [])
982
+ mark("weakness_update_done")
983
+ segs["weakness_update_done"] = (time.perf_counter() - t_w0) * 1000.0
984
+
985
+ t_c0 = time.perf_counter()
986
  cognitive_state = update_cognitive_state_from_message(message, cognitive_state)
987
+ mark("cognitive_update_done")
988
+ segs["cognitive_update_done"] = (time.perf_counter() - t_c0) * 1000.0
989
 
990
+ # RAG
991
+ t_r0 = time.perf_counter()
992
  if is_academic_query(message):
993
  rag_context_text, rag_used_chunks = retrieve_relevant_chunks(
994
  message, rag_chunks or []
995
  )
996
  else:
997
  rag_context_text, rag_used_chunks = "", []
998
+ mark("rag_retrieve_done")
999
+ segs["rag_retrieve_done"] = (time.perf_counter() - t_r0) * 1000.0
1000
 
1001
+ # LLM (chat_with_clare must return 3 values)
1002
+ t_llm0 = time.perf_counter()
1003
+ answer, new_history, llm_stats = chat_with_clare(
1004
  message=message,
1005
  history=chat_history,
1006
  model_name=model_name_val,
 
1012
  cognitive_state=cognitive_state,
1013
  rag_context=rag_context_text,
1014
  )
1015
+ mark("llm_done")
1016
+ segs["llm_done"] = (time.perf_counter() - t_llm0) * 1000.0
1017
+
1018
+ # merge llm_stats into perf
1019
+ perf = {
1020
+ "marks_ms": marks,
1021
+ "segments_ms": segs,
1022
+ "total_ms": marks.get("llm_done", (time.perf_counter() - t0) * 1000.0),
1023
+ }
1024
 
1025
+ # llm_stats may contain marks_ms/segments_ms/llm_profile
1026
+ if isinstance(llm_stats, dict):
1027
+ if "llm_profile" in llm_stats:
1028
+ perf.update({"llm_profile": llm_stats.get("llm_profile", {})})
1029
+ # merge marks/segments from llm_stats if present
1030
+ ms2 = llm_stats.get("marks_ms") if isinstance(llm_stats.get("marks_ms"), dict) else {}
1031
+ sg2 = llm_stats.get("segments_ms") if isinstance(llm_stats.get("segments_ms"), dict) else {}
1032
+ for k, v in ms2.items():
1033
+ if v is not None:
1034
+ perf["marks_ms"][k] = v
1035
+ for k, v in sg2.items():
1036
+ if v is not None:
1037
+ perf["segments_ms"][k] = v
1038
+
1039
+ # References formatting
1040
  if is_academic_query(message) and rag_used_chunks:
1041
  ref_text = format_references(rag_used_chunks)
1042
  else:
 
1049
  new_history[-1] = [last_user, last_assistant]
1050
  answer = last_assistant
1051
 
1052
+ # LangSmith event
1053
  student_id = user_id_val or "ANON"
1054
  experiment_id = "RESP_AI_W10"
1055
  try:
 
1058
  "experiment_id": experiment_id,
1059
  "student_id": student_id,
1060
  "event_type": "chat_turn",
1061
+ "timestamp": time.time(),
1062
+ "latency_ms": perf["total_ms"],
1063
  "question": message,
1064
  "answer": answer,
1065
  "model_name": model_name_val,
1066
  "language": resolved_lang,
1067
  "learning_mode": mode_val,
1068
+ # ✅ extra profiling fields if available
1069
+ "ttft_ms": perf.get("segments_ms", {}).get("llm_ttft_ms"),
1070
+ "tokens_per_sec": (perf.get("llm_profile", {}) or {}).get("tokens_per_sec_est"),
1071
+ "output_tokens_est": (perf.get("llm_profile", {}) or {}).get("output_tokens_est"),
1072
+ "streaming_used": (perf.get("llm_profile", {}) or {}).get("streaming_used"),
1073
  }
1074
  )
1075
  except Exception as e:
 
1089
  False,
1090
  gr.update(interactive=True, value="👍 Helpful"),
1091
  gr.update(interactive=True, value="👎 Not helpful"),
1092
+ perf, # ✅ perf_state
1093
+ perf, # ✅ perf_output
1094
  )
1095
 
1096
  user_input.submit(
 
1120
  feedback_used_state,
1121
  thumb_up_btn,
1122
  thumb_down_btn,
1123
+ perf_state, # ✅
1124
+ perf_output, # ✅
1125
  ],
1126
  )
1127
 
 
1138
  doc_type_val,
1139
  user_id_val,
1140
  ):
1141
+ t0 = time.perf_counter()
1142
+ marks = {"start": 0}
1143
+ segs = {}
1144
+
1145
+ def mark(name: str):
1146
+ marks[name] = (time.perf_counter() - t0) * 1000.0
1147
+
1148
  if not user_id_val:
1149
  gr.Info("Please log in first to start a micro-quiz.", title="Login required")
1150
+ perf = {"marks_ms": marks, "segments_ms": segs, "total_ms": (time.perf_counter() - t0) * 1000.0}
1151
  return (
1152
  chat_history,
1153
  weaknesses,
 
1157
  weaknesses or [],
1158
  cognitive_state or {"confusion": 0, "mastery": 0},
1159
  ),
1160
+ perf,
1161
+ perf,
1162
  )
1163
 
1164
  quiz_instruction = (
 
1189
  )
1190
 
1191
  resolved_lang = lang_pref
1192
+ mark("language_detect_done")
1193
+ segs["language_detect_done"] = marks["language_detect_done"]
1194
 
1195
+ t_r0 = time.perf_counter()
1196
  quiz_ctx_text, _quiz_ctx_chunks = retrieve_relevant_chunks(
1197
  "Module 10 quiz", rag_chunks or []
1198
  )
1199
+ mark("rag_retrieve_done")
1200
+ segs["rag_retrieve_done"] = (time.perf_counter() - t_r0) * 1000.0
1201
 
1202
+ t_llm0 = time.perf_counter()
1203
+ answer, new_history, llm_stats = chat_with_clare(
1204
  message=quiz_instruction,
1205
  history=chat_history,
1206
  model_name=model_name_val,
 
1212
  cognitive_state=cognitive_state,
1213
  rag_context=quiz_ctx_text,
1214
  )
1215
+ mark("llm_done")
1216
+ segs["llm_done"] = (time.perf_counter() - t_llm0) * 1000.0
1217
+
1218
+ perf = {
1219
+ "marks_ms": marks,
1220
+ "segments_ms": segs,
1221
+ "total_ms": marks.get("llm_done", (time.perf_counter() - t0) * 1000.0),
1222
+ }
1223
+ if isinstance(llm_stats, dict):
1224
+ if "llm_profile" in llm_stats:
1225
+ perf.update({"llm_profile": llm_stats.get("llm_profile", {})})
1226
+ ms2 = llm_stats.get("marks_ms") if isinstance(llm_stats.get("marks_ms"), dict) else {}
1227
+ sg2 = llm_stats.get("segments_ms") if isinstance(llm_stats.get("segments_ms"), dict) else {}
1228
+ for k, v in ms2.items():
1229
+ if v is not None:
1230
+ perf["marks_ms"][k] = v
1231
+ for k, v in sg2.items():
1232
+ if v is not None:
1233
+ perf["segments_ms"][k] = v
1234
 
1235
  student_id = user_id_val or "ANON"
1236
  experiment_id = "RESP_AI_W10"
 
1237
  try:
1238
  log_event(
1239
  {
1240
  "experiment_id": experiment_id,
1241
  "student_id": student_id,
1242
  "event_type": "micro_quiz_start",
1243
+ "timestamp": time.time(),
1244
+ "latency_ms": perf["total_ms"],
1245
  "question": quiz_instruction,
1246
  "answer": answer,
1247
  "model_name": model_name_val,
1248
  "language": resolved_lang,
1249
  "learning_mode": mode_val,
1250
+ "ttft_ms": perf.get("segments_ms", {}).get("llm_ttft_ms"),
1251
  }
1252
  )
1253
  except Exception as e:
1254
  print("log_event error:", e)
1255
 
1256
  new_status = render_session_status(mode_val, weaknesses, cognitive_state)
1257
+ return new_history, weaknesses, cognitive_state, new_status, perf, perf
1258
 
1259
  quiz_btn.click(
1260
  start_micro_quiz,
 
1270
  doc_type,
1271
  user_id_state,
1272
  ],
1273
+ [chatbot, weakness_state, cognitive_state_state, session_status, perf_state, perf_output],
1274
  )
1275
 
1276
  # ===== Feedback Handlers (thumb + detailed) =====
 
1500
  False,
1501
  gr.update(interactive=False, value="👍 Helpful"),
1502
  gr.update(interactive=False, value="👎 Not helpful"),
1503
+ {},
1504
+ {},
1505
  )
1506
 
1507
  clear_btn.click(
 
1519
  feedback_used_state,
1520
  thumb_up_btn,
1521
  thumb_down_btn,
1522
+ perf_state,
1523
+ perf_output,
1524
  ],
1525
  queue=False,
1526
  )