SarahXia0405 commited on
Commit
9cea95c
·
verified ·
1 Parent(s): eaa41b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -107
app.py CHANGED
@@ -69,71 +69,23 @@ CUSTOM_CSS = """
69
  border-bottom: 2px solid #f3f4f6; margin-bottom: 15px;
70
  }
71
 
72
- /* --- User Guide 美化 (无框风格) --- */
73
- .user-guide-group {
74
- border: none !important;
75
- background: transparent !important;
76
- }
77
- /* 针对子项 Accordion 的样式覆盖 */
78
- .clean-accordion {
79
- border: none !important;
80
- background: transparent !important;
81
- box-shadow: none !important;
82
- margin-bottom: 0px !important;
83
- padding: 0 !important;
84
- }
85
- /* 修改 Accordion 标题栏样式 */
86
- .clean-accordion > .label-wrap {
87
- border: none !important;
88
- background: transparent !important;
89
- padding: 8px 0 !important;
90
- font-size: 0.95rem !important;
91
- font-weight: 500 !important;
92
- color: #374151 !important;
93
- border-bottom: 1px solid #f3f4f6 !important; /* 淡淡的分隔线 */
94
- }
95
- .clean-accordion > .label-wrap:hover {
96
- color: #000 !important;
97
- background: #f9fafb !important;
98
- }
99
 
100
- /* --- Action 按钮加粗 --- */
101
- .action-btn {
102
- font-weight: bold !important;
103
- font-size: 0.9rem !important;
104
- position: relative;
105
- overflow: visible !important;
106
- }
107
-
108
- /* Tooltip (Actions) */
109
- .action-btn:hover::before {
110
- content: "See User Guide for details";
111
- position: absolute; bottom: 110%; left: 50%; transform: translateX(-50%);
112
- background-color: #333; color: #fff; padding: 5px 10px; border-radius: 5px;
113
- font-size: 12px; white-space: nowrap; z-index: 1000; pointer-events: none; opacity: 0; animation: fadeIn 0.2s forwards;
114
- }
115
- .action-btn:hover::after {
116
- content: ""; position: absolute; bottom: 100%; left: 50%; margin-left: -5px;
117
- border-width: 5px; border-style: solid; border-color: #333 transparent transparent transparent;
118
- opacity: 0; animation: fadeIn 0.2s forwards;
119
- }
120
 
121
  /* HTML Tooltip (Memory Line) */
122
- .html-tooltip {
123
- border-bottom: 1px dashed #999; cursor: help; position: relative;
124
- }
125
- .html-tooltip:hover::before {
126
- content: attr(data-tooltip);
127
- position: absolute; bottom: 120%; left: 0; background-color: #333; color: #fff;
128
- padding: 5px 8px; border-radius: 4px; font-size: 11px; white-space: nowrap; z-index: 100; pointer-events: none;
129
- }
130
 
131
  /* Memory Line Box */
132
- .memory-line-box {
133
- border: 1px solid #e5e7eb; padding: 12px; border-radius: 8px;
134
- background-color: #f9fafb; height: 100%;
135
- display: flex; flex-direction: column; justify-content: space-between;
136
- }
137
 
138
  @keyframes fadeIn { to { opacity: 1; } }
139
  """
@@ -148,7 +100,7 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
148
  cognitive_state_state = gr.State({"confusion": 0, "mastery": 0})
149
  rag_chunks_state = gr.State([])
150
 
151
- # 1. Header
152
  gr.HTML(
153
  f"""
154
  <div class="header-container">
@@ -166,8 +118,9 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
166
  </div>
167
  <div style="text-align: right;">
168
  <img src="{image_to_base64(HANBRIDGE_LOGO_PATH)}" style="height: 55px; object-fit: contain; margin-bottom: 5px;">
169
- <div style="font-size: 12px; color: #666;">
170
- 🎓 (Student Name) (Student Email/ID)
 
171
  </div>
172
  </div>
173
  </div>
@@ -181,9 +134,8 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
181
  with gr.Column(scale=1, min_width=200):
182
  clear_btn = gr.Button("Reset Conversation", variant="stop")
183
 
184
- # Model Settings
185
  gr.Markdown("### Model Settings")
186
- # 锁定 Model,不可修改
187
  model_name = gr.Textbox(label="Model", value="gpt-4.1-mini", interactive=False, lines=1)
188
  language_preference = gr.Radio(choices=["Auto", "English", "简体中文"], value="Auto", label="Language")
189
 
@@ -194,55 +146,53 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
194
  info="See User Guide for mode definitions details."
195
  )
196
 
197
- # User Guide (美化版 - 无框风格)
198
  with gr.Accordion("User Guide", open=True, elem_classes="user-guide-group"):
199
- # 给每个子项加上 elem_classes="clean-accordion" 以去除边框
200
- with gr.Accordion("Getting Started", open=False, elem_classes="clean-accordion"):
201
- gr.Markdown(USER_GUIDE_SECTIONS["getting_started"])
202
- with gr.Accordion("Mode Definition", open=False, elem_classes="clean-accordion"):
203
- gr.Markdown(USER_GUIDE_SECTIONS["mode_definition"])
204
- with gr.Accordion("How Clare Works", open=False, elem_classes="clean-accordion"):
205
- gr.Markdown(USER_GUIDE_SECTIONS["how_clare_works"])
206
- with gr.Accordion("What is Memory Line", open=False, elem_classes="clean-accordion"):
207
- gr.Markdown(USER_GUIDE_SECTIONS["memory_line"])
208
- with gr.Accordion("Learning Progress Report", open=False, elem_classes="clean-accordion"):
209
- gr.Markdown(USER_GUIDE_SECTIONS["learning_progress"])
210
- with gr.Accordion("How Clare Uses Your Files", open=False, elem_classes="clean-accordion"):
211
- gr.Markdown(USER_GUIDE_SECTIONS["how_files"])
212
- with gr.Accordion("Micro-Quiz", open=False, elem_classes="clean-accordion"):
213
- gr.Markdown(USER_GUIDE_SECTIONS["micro_quiz"])
214
- with gr.Accordion("Summarization", open=False, elem_classes="clean-accordion"):
215
- gr.Markdown(USER_GUIDE_SECTIONS["summarization"])
216
- with gr.Accordion("Export Conversation", open=False, elem_classes="clean-accordion"):
217
- gr.Markdown(USER_GUIDE_SECTIONS["export_conversation"])
218
- with gr.Accordion("FAQ", open=False, elem_classes="clean-accordion"):
219
- gr.Markdown(USER_GUIDE_SECTIONS["faq"])
220
 
221
- # System Settings / Log Out (去掉 gr.Group 框,简洁排列)
222
- gr.Markdown("---") # 分割线
223
- with gr.Row():
224
- gr.Button("System Settings", size="sm", variant="secondary")
225
- gr.Button("Log Out", size="sm", variant="secondary")
 
 
 
 
 
 
 
226
 
227
  # === [Center Main] ===
228
  with gr.Column(scale=3):
229
 
230
- # Upload & Memory Line
231
- # 这一行高度大约是 130px - 150px
232
  with gr.Row():
233
- # Upload
234
  with gr.Column(scale=1):
235
- # 增加 height 以防文字看不全,或者不设 height 让它自适应
236
- # 这里设置为 None 让其自适应内容,或者稍微加大一点比如 120
237
  syllabus_file = gr.File(
238
  file_types=[".docx", ".pdf", ".pptx"],
239
  file_count="single",
240
- height=120, # 稍微调高一点
241
- label="Upload file (.docx/.pdf/.pptx)" # Label 放在这里
242
  )
243
- doc_type = gr.Dropdown(choices=DOC_TYPES, value="Syllabus", label="File type", container=False)
 
 
 
 
244
 
245
- # Memory Line
246
  with gr.Column(scale=1):
247
  with gr.Group(elem_classes="memory-line-box"):
248
  gr.HTML(
@@ -264,7 +214,7 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
264
  review_btn = gr.Button("Review Now", size="sm", variant="primary")
265
  session_status = gr.Markdown(visible=False)
266
 
267
- # Chat
268
  gr.Markdown(
269
  """
270
  <div style="background-color:#f9fafb; padding:10px; border-radius:5px; margin-top:10px; font-size:0.9em; color:#555;">
@@ -279,14 +229,12 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
279
  # === [Right Sidebar] ===
280
  with gr.Column(scale=1, min_width=180):
281
 
282
- # --- 占位符 Spacer ---
283
- # 这是一个看不见的盒子,高度设为 165px (大约等于 Upload + Memory Line + Padding 的高度)
284
- # 作用是把下面的 Actions 顶下去,使其与 Chatbot 顶部对齐
285
- gr.HTML("<div style='height: 165px; width: 100%;'></div>")
286
 
287
  gr.Markdown("### Actions")
288
 
289
- # Action Buttons (加粗 + 悬停提示)
290
  export_btn = gr.Button("Export Conversation", size="sm", elem_classes="action-btn")
291
  quiz_btn = gr.Button("Let's Try (Micro-Quiz)", size="sm", elem_classes="action-btn")
292
  summary_btn = gr.Button("Summarization", size="sm", elem_classes="action-btn")
@@ -304,6 +252,9 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
304
 
305
  syllabus_file.change(update_course_and_rag, [syllabus_file, doc_type], [course_outline_state, rag_chunks_state, session_status])
306
 
 
 
 
307
  def respond(message, chat_history, course_outline, weaknesses, cognitive_state, rag_chunks, model, lang, mode, doc_type_val):
308
  resolved_lang = detect_language(message or "", lang)
309
  if not message or not message.strip():
 
69
  border-bottom: 2px solid #f3f4f6; margin-bottom: 15px;
70
  }
71
 
72
+ /* User Guide 美化 (无框风格) */
73
+ .user-guide-group { border: none !important; background: transparent !important; }
74
+ .clean-accordion { border: none !important; background: transparent !important; box-shadow: none !important; margin-bottom: 0px !important; padding: 0 !important; }
75
+ .clean-accordion > .label-wrap { border: none !important; background: transparent !important; padding: 8px 0 !important; font-size: 0.95rem !important; font-weight: 500 !important; color: #374151 !important; border-bottom: 1px solid #f3f4f6 !important; }
76
+ .clean-accordion > .label-wrap:hover { color: #000 !important; background: #f9fafb !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
+ /* Action 按钮加粗 & Tooltip */
79
+ .action-btn { font-weight: bold !important; font-size: 0.9rem !important; position: relative; overflow: visible !important; }
80
+ .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; }
81
+ .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; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
  /* HTML Tooltip (Memory Line) */
84
+ .html-tooltip { border-bottom: 1px dashed #999; cursor: help; position: relative; }
85
+ .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; }
 
 
 
 
 
 
86
 
87
  /* Memory Line Box */
88
+ .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; }
 
 
 
 
89
 
90
  @keyframes fadeIn { to { opacity: 1; } }
91
  """
 
100
  cognitive_state_state = gr.State({"confusion": 0, "mastery": 0})
101
  rag_chunks_state = gr.State([])
102
 
103
+ # 1. Header (包含右上角 Log Out)
104
  gr.HTML(
105
  f"""
106
  <div class="header-container">
 
118
  </div>
119
  <div style="text-align: right;">
120
  <img src="{image_to_base64(HANBRIDGE_LOGO_PATH)}" style="height: 55px; object-fit: contain; margin-bottom: 5px;">
121
+ <div style="font-size: 12px; color: #666; margin-top: 4px; display:flex; align-items:center; justify-content:flex-end; gap:12px;">
122
+ <span>🎓 (Student Name) (Student Email/ID)</span>
123
+ <a href="#" style="color: #000; font-weight: bold; text-decoration: underline; font-size: 12px;">Log Out</a>
124
  </div>
125
  </div>
126
  </div>
 
134
  with gr.Column(scale=1, min_width=200):
135
  clear_btn = gr.Button("Reset Conversation", variant="stop")
136
 
137
+ # Model Settings (Locked)
138
  gr.Markdown("### Model Settings")
 
139
  model_name = gr.Textbox(label="Model", value="gpt-4.1-mini", interactive=False, lines=1)
140
  language_preference = gr.Radio(choices=["Auto", "English", "简体中文"], value="Auto", label="Language")
141
 
 
146
  info="See User Guide for mode definitions details."
147
  )
148
 
149
+ # User Guide (无框列表风格)
150
  with gr.Accordion("User Guide", open=True, elem_classes="user-guide-group"):
151
+ with gr.Accordion("Getting Started", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["getting_started"])
152
+ with gr.Accordion("Mode Definition", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["mode_definition"])
153
+ with gr.Accordion("How Clare Works", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["how_clare_works"])
154
+ with gr.Accordion("What is Memory Line", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["memory_line"])
155
+ with gr.Accordion("Learning Progress Report", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["learning_progress"])
156
+ with gr.Accordion("How Clare Uses Your Files", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["how_files"])
157
+ with gr.Accordion("Micro-Quiz", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["micro_quiz"])
158
+ with gr.Accordion("Summarization", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["summarization"])
159
+ with gr.Accordion("Export Conversation", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["export_conversation"])
160
+ with gr.Accordion("FAQ", open=False, elem_classes="clean-accordion"): gr.Markdown(USER_GUIDE_SECTIONS["faq"])
 
 
 
 
 
 
 
 
 
 
 
161
 
162
+ # 底部 Settings & Copyright
163
+ gr.Markdown("---")
164
+ gr.Button("System Settings", size="sm", variant="secondary")
165
+
166
+ # 署名 (Footer)
167
+ gr.HTML(
168
+ """
169
+ <div style="font-size: 11px; color: #9ca3af; margin-top: 15px; text-align: left;">
170
+ © 2025 Made by <a href="https://www.linkedin.com/in/qinghua-xia-479199252/" target="_blank" style="color: #6b7280; text-decoration: underline;">Sarah Xia</a>
171
+ </div>
172
+ """
173
+ )
174
 
175
  # === [Center Main] ===
176
  with gr.Column(scale=3):
177
 
178
+ # Upload & Memory Line Row
 
179
  with gr.Row():
180
+ # Upload Column
181
  with gr.Column(scale=1):
182
+ # 调大高度 height=160
 
183
  syllabus_file = gr.File(
184
  file_types=[".docx", ".pdf", ".pptx"],
185
  file_count="single",
186
+ height=160,
187
+ label="Upload file (.docx/.pdf/.pptx)"
188
  )
189
+ # 下拉框 + 查看文档按钮
190
+ with gr.Row():
191
+ doc_type = gr.Dropdown(choices=DOC_TYPES, value="Syllabus", label="File type", container=False, scale=3)
192
+ # 这里添加 "Loaded Docs" 按钮/指示器
193
+ docs_btn = gr.Button("📂 Loaded Docs", size="sm", variant="secondary", scale=2, min_width=80)
194
 
195
+ # Memory Line Column
196
  with gr.Column(scale=1):
197
  with gr.Group(elem_classes="memory-line-box"):
198
  gr.HTML(
 
214
  review_btn = gr.Button("Review Now", size="sm", variant="primary")
215
  session_status = gr.Markdown(visible=False)
216
 
217
+ # Chat Interface
218
  gr.Markdown(
219
  """
220
  <div style="background-color:#f9fafb; padding:10px; border-radius:5px; margin-top:10px; font-size:0.9em; color:#555;">
 
229
  # === [Right Sidebar] ===
230
  with gr.Column(scale=1, min_width=180):
231
 
232
+ # 占位符:用于将 Actions 向下推,与 Chatbox 顶部对齐
233
+ # 上传区+MemoryLine 大约高度160px + Gap,设置 200px 左右比较稳妥
234
+ gr.HTML("<div style='height: 210px; width: 100%;'></div>")
 
235
 
236
  gr.Markdown("### Actions")
237
 
 
238
  export_btn = gr.Button("Export Conversation", size="sm", elem_classes="action-btn")
239
  quiz_btn = gr.Button("Let's Try (Micro-Quiz)", size="sm", elem_classes="action-btn")
240
  summary_btn = gr.Button("Summarization", size="sm", elem_classes="action-btn")
 
252
 
253
  syllabus_file.change(update_course_and_rag, [syllabus_file, doc_type], [course_outline_state, rag_chunks_state, session_status])
254
 
255
+ # 简单的 Loaded Docs 提示逻辑
256
+ docs_btn.click(lambda: gr.Info("Current Context: Syllabus.pdf (Uploaded), Course_Intro.docx (System)", title="Loaded Documents"))
257
+
258
  def respond(message, chat_history, course_outline, weaknesses, cognitive_state, rag_chunks, model, lang, mode, doc_type_val):
259
  resolved_lang = detect_language(message or "", lang)
260
  if not message or not message.strip():