Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -195,6 +195,43 @@ def describe_cognitive_state(state: Optional[Dict[str, int]]) -> str:
|
|
| 195 |
return "mixed or uncertain cognitive state."
|
| 196 |
|
| 197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
# ---------- Same Question Check helpers ----------
|
| 199 |
def _normalize_text(text: str) -> str:
|
| 200 |
"""
|
|
@@ -708,9 +745,15 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant") as demo:
|
|
| 708 |
def update_outline(file, doc_type_val):
|
| 709 |
if file is None:
|
| 710 |
return DEFAULT_COURSE_TOPICS
|
| 711 |
-
|
| 712 |
-
|
| 713 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 714 |
# 其他类型文件目前不解析,只保留默认大纲
|
| 715 |
return DEFAULT_COURSE_TOPICS
|
| 716 |
|
|
@@ -720,10 +763,16 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant") as demo:
|
|
| 720 |
outputs=[course_outline_state],
|
| 721 |
)
|
| 722 |
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 727 |
user_input = gr.Textbox(
|
| 728 |
label="Your question",
|
| 729 |
placeholder="Ask Clare anything about your course, assignment, or study plan...",
|
|
@@ -760,6 +809,9 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant") as demo:
|
|
| 760 |
learning_mode_val,
|
| 761 |
doc_type_val,
|
| 762 |
):
|
|
|
|
|
|
|
|
|
|
| 763 |
# 先更新弱项和认知状态
|
| 764 |
weaknesses = update_weaknesses_from_message(message, weaknesses or [])
|
| 765 |
cognitive_state = update_cognitive_state_from_message(message, cognitive_state)
|
|
@@ -781,27 +833,31 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant") as demo:
|
|
| 781 |
"如果还有具体不清楚的地方,可以告诉我,我会换一种方式解释。\n\n"
|
| 782 |
"**之前的回答:**\n"
|
| 783 |
)
|
| 784 |
-
if
|
| 785 |
answer = prefix_zh + past_a
|
| 786 |
else:
|
| 787 |
answer = prefix_en + past_a
|
| 788 |
|
| 789 |
new_history = chat_history + [(message, answer)]
|
| 790 |
-
|
|
|
|
|
|
|
| 791 |
|
| 792 |
# ---------- 正常调用 Clare ----------
|
| 793 |
answer, new_history = chat_with_clare(
|
| 794 |
message=message,
|
| 795 |
history=chat_history,
|
| 796 |
model_name=model_name_val,
|
| 797 |
-
language_preference=
|
| 798 |
learning_mode=learning_mode_val,
|
| 799 |
doc_type=doc_type_val,
|
| 800 |
course_outline=course_outline,
|
| 801 |
weaknesses=weaknesses,
|
| 802 |
cognitive_state=cognitive_state,
|
| 803 |
)
|
| 804 |
-
|
|
|
|
|
|
|
| 805 |
|
| 806 |
user_input.submit(
|
| 807 |
respond,
|
|
@@ -816,17 +872,19 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant") as demo:
|
|
| 816 |
learning_mode,
|
| 817 |
doc_type,
|
| 818 |
],
|
| 819 |
-
[user_input, chatbot, weakness_state, cognitive_state_state],
|
| 820 |
)
|
| 821 |
|
| 822 |
# 清空对话 & 状态 & 导出/quiz/summary
|
| 823 |
def clear_all():
|
| 824 |
-
|
|
|
|
|
|
|
| 825 |
|
| 826 |
clear_btn.click(
|
| 827 |
clear_all,
|
| 828 |
None,
|
| 829 |
-
[chatbot, weakness_state, cognitive_state_state, export_box, quiz_box, summary_box],
|
| 830 |
queue=False,
|
| 831 |
)
|
| 832 |
|
|
@@ -909,4 +967,4 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant") as demo:
|
|
| 909 |
)
|
| 910 |
|
| 911 |
if __name__ == "__main__":
|
| 912 |
-
demo.launch()
|
|
|
|
| 195 |
return "mixed or uncertain cognitive state."
|
| 196 |
|
| 197 |
|
| 198 |
+
# ---------- 语言检测(用于 Auto 模式) ----------
|
| 199 |
+
def detect_language(message: str, preference: str) -> str:
|
| 200 |
+
"""
|
| 201 |
+
preference:
|
| 202 |
+
- 'English' → 强制英文
|
| 203 |
+
- '中文' → 强制中文
|
| 204 |
+
- 'Auto' → 检测文本是否包含中文字符
|
| 205 |
+
"""
|
| 206 |
+
if preference in ("English", "中文"):
|
| 207 |
+
return preference
|
| 208 |
+
# Auto 模式下简单检测是否含有中文字符
|
| 209 |
+
if re.search(r"[\u4e00-\u9fff]", message):
|
| 210 |
+
return "中文"
|
| 211 |
+
return "English"
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
# ---------- Session 状态展示 ----------
|
| 215 |
+
def render_session_status(
|
| 216 |
+
learning_mode: str,
|
| 217 |
+
weaknesses: Optional[List[str]],
|
| 218 |
+
cognitive_state: Optional[Dict[str, int]],
|
| 219 |
+
) -> str:
|
| 220 |
+
lines: List[str] = []
|
| 221 |
+
lines.append("### Session status\n")
|
| 222 |
+
lines.append(f"- Learning mode: **{learning_mode}**")
|
| 223 |
+
lines.append(f"- Cognitive state: {describe_cognitive_state(cognitive_state)}")
|
| 224 |
+
|
| 225 |
+
if weaknesses:
|
| 226 |
+
lines.append("- Recent difficulties (last 3):")
|
| 227 |
+
for w in weaknesses[-3:]:
|
| 228 |
+
lines.append(f" - {w}")
|
| 229 |
+
else:
|
| 230 |
+
lines.append("- Recent difficulties: *(none yet)*")
|
| 231 |
+
|
| 232 |
+
return "\n".join(lines)
|
| 233 |
+
|
| 234 |
+
|
| 235 |
# ---------- Same Question Check helpers ----------
|
| 236 |
def _normalize_text(text: str) -> str:
|
| 237 |
"""
|
|
|
|
| 745 |
def update_outline(file, doc_type_val):
|
| 746 |
if file is None:
|
| 747 |
return DEFAULT_COURSE_TOPICS
|
| 748 |
+
# Gradio File 默认传的是一个带 .name 的临时文件对象
|
| 749 |
+
if doc_type_val == "Syllabus":
|
| 750 |
+
try:
|
| 751 |
+
file_path = file.name # 临时文件真实路径
|
| 752 |
+
if file_path.lower().endswith(".docx"):
|
| 753 |
+
topics = parse_syllabus_docx(file_path)
|
| 754 |
+
return topics
|
| 755 |
+
except Exception:
|
| 756 |
+
return DEFAULT_COURSE_TOPICS
|
| 757 |
# 其他类型文件目前不解析,只保留默认大纲
|
| 758 |
return DEFAULT_COURSE_TOPICS
|
| 759 |
|
|
|
|
| 763 |
outputs=[course_outline_state],
|
| 764 |
)
|
| 765 |
|
| 766 |
+
with gr.Row():
|
| 767 |
+
chatbot = gr.Chatbot(
|
| 768 |
+
label="Clare Chat",
|
| 769 |
+
height=450,
|
| 770 |
+
)
|
| 771 |
+
session_status = gr.Markdown(
|
| 772 |
+
value=render_session_status("Concept Explainer", [], {"confusion": 0, "mastery": 0}),
|
| 773 |
+
label="Session status",
|
| 774 |
+
)
|
| 775 |
+
|
| 776 |
user_input = gr.Textbox(
|
| 777 |
label="Your question",
|
| 778 |
placeholder="Ask Clare anything about your course, assignment, or study plan...",
|
|
|
|
| 809 |
learning_mode_val,
|
| 810 |
doc_type_val,
|
| 811 |
):
|
| 812 |
+
# 先根据 Auto / English / 中文 决定本轮用什么语言
|
| 813 |
+
resolved_lang = detect_language(message, language_pref_val)
|
| 814 |
+
|
| 815 |
# 先更新弱项和认知状态
|
| 816 |
weaknesses = update_weaknesses_from_message(message, weaknesses or [])
|
| 817 |
cognitive_state = update_cognitive_state_from_message(message, cognitive_state)
|
|
|
|
| 833 |
"如果还有具体不清楚的地方,可以告诉我,我会换一种方式解释。\n\n"
|
| 834 |
"**之前的回答:**\n"
|
| 835 |
)
|
| 836 |
+
if resolved_lang == "中文":
|
| 837 |
answer = prefix_zh + past_a
|
| 838 |
else:
|
| 839 |
answer = prefix_en + past_a
|
| 840 |
|
| 841 |
new_history = chat_history + [(message, answer)]
|
| 842 |
+
status_text = render_session_status(learning_mode_val, weaknesses, cognitive_state)
|
| 843 |
+
# 清空输入框,更新 history / 弱项 / 认知状态 / 状态栏
|
| 844 |
+
return "", new_history, weaknesses, cognitive_state, status_text
|
| 845 |
|
| 846 |
# ---------- 正常调用 Clare ----------
|
| 847 |
answer, new_history = chat_with_clare(
|
| 848 |
message=message,
|
| 849 |
history=chat_history,
|
| 850 |
model_name=model_name_val,
|
| 851 |
+
language_preference=resolved_lang,
|
| 852 |
learning_mode=learning_mode_val,
|
| 853 |
doc_type=doc_type_val,
|
| 854 |
course_outline=course_outline,
|
| 855 |
weaknesses=weaknesses,
|
| 856 |
cognitive_state=cognitive_state,
|
| 857 |
)
|
| 858 |
+
|
| 859 |
+
status_text = render_session_status(learning_mode_val, weaknesses, cognitive_state)
|
| 860 |
+
return "", new_history, weaknesses, cognitive_state, status_text
|
| 861 |
|
| 862 |
user_input.submit(
|
| 863 |
respond,
|
|
|
|
| 872 |
learning_mode,
|
| 873 |
doc_type,
|
| 874 |
],
|
| 875 |
+
[user_input, chatbot, weakness_state, cognitive_state_state, session_status],
|
| 876 |
)
|
| 877 |
|
| 878 |
# 清空对话 & 状态 & 导出/quiz/summary
|
| 879 |
def clear_all():
|
| 880 |
+
empty_state = {"confusion": 0, "mastery": 0}
|
| 881 |
+
status_text = render_session_status("Concept Explainer", [], empty_state)
|
| 882 |
+
return [], [], empty_state, "", "", "", status_text
|
| 883 |
|
| 884 |
clear_btn.click(
|
| 885 |
clear_all,
|
| 886 |
None,
|
| 887 |
+
[chatbot, weakness_state, cognitive_state_state, export_box, quiz_box, summary_box, session_status],
|
| 888 |
queue=False,
|
| 889 |
)
|
| 890 |
|
|
|
|
| 967 |
)
|
| 968 |
|
| 969 |
if __name__ == "__main__":
|
| 970 |
+
demo.launch()
|