SarahXia0405 commited on
Commit
8ca5d39
·
verified ·
1 Parent(s): 9e847ec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -26
app.py CHANGED
@@ -1,6 +1,7 @@
1
- # app.py
2
- from typing import List, Dict, Tuple, Optional
3
  import gradio as gr
 
 
 
4
 
5
  from config import (
6
  DEFAULT_MODEL,
@@ -26,10 +27,26 @@ from rag_engine import (
26
  )
27
  from syllabus_utils import extract_course_topics_from_file
28
 
29
- # ================== Assets (图片路径配置) ==================
30
  HANBRIDGE_LOGO_PATH = "hanbridge_logo.png"
31
  CLARE_LOGO_PATH = "clare_mascot.png"
32
- CLARE_RUN_PATH = "Clare_Run.png" # 已取消注释
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  # ================== CSS (样式调整) ==================
35
  CUSTOM_CSS = """
@@ -43,6 +60,7 @@ CUSTOM_CSS = """
43
  border-bottom: 2px solid #f3f4f6;
44
  margin-bottom: 15px;
45
  }
 
46
  /* User Guide 链接样式 */
47
  #user-guide-links button {
48
  background: transparent !important; border: none !important; box-shadow: none !important;
@@ -50,13 +68,14 @@ CUSTOM_CSS = """
50
  color: #004a99 !important; text-decoration: underline; font-size: 0.8rem;
51
  }
52
  #user-guide-links button:hover { color: #002b66 !important; }
 
53
  /* Memory Line 区域样式 */
54
  .memory-line-box {
55
  border: 1px solid #e5e7eb;
56
  padding: 12px;
57
  border-radius: 8px;
58
  background-color: #f9fafb;
59
- height: 100%; /* 填满高度 */
60
  }
61
  """
62
 
@@ -87,13 +106,12 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
87
  cognitive_state_state = gr.State({"confusion": 0, "mastery": 0})
88
  rag_chunks_state = gr.State([])
89
 
90
- # ============ 1. 顶部 Header (全宽布局) ============
91
- # 包含 CLARE_LOGO_PATH (左) 和 HANBRIDGE_LOGO_PATH (右)
92
  gr.HTML(
93
  f"""
94
  <div class="header-container">
95
  <div style="display:flex; align-items:center; gap: 20px;">
96
- <img src="file=clare_mascot.png" style="height: 75px; object-fit: contain;">
97
  <div style="display:flex; flex-direction:column;">
98
  <div style="font-size: 32px; font-weight: 800; line-height: 1.1; color: #000;">
99
  Clare
@@ -104,8 +122,9 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
104
  </div>
105
  </div>
106
  </div>
 
107
  <div style="text-align: right;">
108
- <img src="file/{HANBRIDGE_LOGO_PATH}" style="height: 55px; object-fit: contain; margin-bottom: 5px;">
109
  <div style="font-size: 12px; color: #666;">
110
  🎓 (Student Name) (Student Email/ID)
111
  </div>
@@ -114,12 +133,11 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
114
  """
115
  )
116
 
117
- # ============ 2. 主体分栏布局:左(1) - 中(3) - 右(1) ============
118
  with gr.Row():
119
 
120
  # ============ [左侧] 控制面板 Sidebar ============
121
  with gr.Column(scale=1, min_width=200):
122
- # Reset 按钮
123
  clear_btn = gr.Button("Reset Conversation", variant="stop")
124
 
125
  gr.Markdown("### Model Settings")
@@ -151,7 +169,7 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
151
  # ============ [中间] 主内容区 Center Main ============
152
  with gr.Column(scale=3):
153
 
154
- # 上半部分:上传区(左) + Memory Line(右) 并排
155
  with gr.Row():
156
  # --- Upload File ---
157
  with gr.Column(scale=1):
@@ -168,9 +186,8 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
168
  container=False
169
  )
170
 
171
- # --- Memory Line (包含 CLARE_RUN_PATH) ---
172
  with gr.Column(scale=1):
173
- # 使用 HTML 渲染带图片的进度条
174
  gr.HTML(
175
  f"""
176
  <div class="memory-line-box">
@@ -181,8 +198,9 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
181
  <div style="position: relative; height: 35px; margin-top: 15px; margin-bottom: 5px;">
182
  <div style="position: absolute; bottom: 5px; left: 0; width: 100%; height: 8px; background-color: #e5e7eb; border-radius: 4px;"></div>
183
  <div style="position: absolute; bottom: 5px; left: 0; width: 40%; height: 8px; background-color: #8B1A1A; border-radius: 4px 0 0 4px;"></div>
184
- <img src="file/{CLARE_RUN_PATH}" style="position: absolute; left: 36%; bottom: 8px; height: 35px; z-index: 10;">
185
  </div>
 
186
  <div style="display:flex; justify-content:space-between; align-items:center; margin-top:8px;">
187
  <div style="font-size: 12px; color: #666;">Next Review: T+7</div>
188
  <div style="font-size: 12px; color: #004a99; text-decoration:underline; cursor:pointer;">
@@ -192,10 +210,7 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
192
  </div>
193
  """
194
  )
195
- # 真实的 Review 按钮放在 HTML 下方
196
  review_btn = gr.Button("Review Now", size="sm", variant="primary")
197
-
198
- # 隐藏的 Session Status 用于逻辑传递
199
  session_status = gr.Markdown(visible=False)
200
 
201
  # --- Chat Interface ---
@@ -211,7 +226,10 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
211
  chatbot = gr.Chatbot(
212
  label="",
213
  height=450,
214
- avatar_images=(None, CLARE_LOGO_PATH), # 聊天框内的头像
 
 
 
215
  show_label=False,
216
  bubble_full_width=False
217
  )
@@ -227,7 +245,6 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
227
  # ============ [右侧] 功能栏 Right Sidebar ============
228
  with gr.Column(scale=1, min_width=180):
229
  gr.Markdown("### Actions")
230
-
231
  export_btn = gr.Button("Export Conversation", size="sm")
232
  quiz_btn = gr.Button("Let's Try (Micro-Quiz)", size="sm")
233
  summary_btn = gr.Button("Summarization", size="sm")
@@ -240,9 +257,8 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
240
  show_label=False
241
  )
242
 
243
- # ================== Logic Bindings ==================
244
 
245
- # 1. File Upload Logic
246
  def update_course_and_rag(file, doc_type_val):
247
  topics = extract_course_topics_from_file(file, doc_type_val)
248
  rag_chunks = build_rag_chunks_from_file(file, doc_type_val)
@@ -255,7 +271,6 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
255
  outputs=[course_outline_state, rag_chunks_state, session_status],
256
  )
257
 
258
- # 2. Chat Logic
259
  def respond(message, chat_history, course_outline, weaknesses, cognitive_state, rag_chunks, model, lang, mode, doc_type_val):
260
  resolved_lang = detect_language(message or "", lang)
261
 
@@ -288,7 +303,6 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
288
  [user_input, chatbot, weakness_state, cognitive_state_state, session_status]
289
  )
290
 
291
- # 3. Action Buttons Logic
292
  def on_export(chat_history, course_outline, mode, weaknesses, cognitive_state):
293
  return export_conversation(chat_history, course_outline, mode, weaknesses, cognitive_state)
294
 
@@ -316,7 +330,6 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
316
  [result_display]
317
  )
318
 
319
- # 4. Reset Logic
320
  def clear_all():
321
  empty_state = {"confusion": 0, "mastery": 0}
322
  default_status = render_session_status("Concept Explainer", [], empty_state)
@@ -329,7 +342,6 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
329
  queue=False
330
  )
331
 
332
- # 5. User Guide Logic
333
  def show_guide(section):
334
  return get_user_guide_section(section)
335
 
@@ -339,4 +351,5 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
339
  ug_memory_line.click(lambda: show_guide("memory_line"), outputs=result_display)
340
 
341
  if __name__ == "__main__":
 
342
  demo.launch()
 
 
 
1
  import gradio as gr
2
+ import os
3
+ import base64
4
+ from typing import List, Dict, Tuple, Optional
5
 
6
  from config import (
7
  DEFAULT_MODEL,
 
27
  )
28
  from syllabus_utils import extract_course_topics_from_file
29
 
30
+ # ================== Assets (图片路径) ==================
31
  HANBRIDGE_LOGO_PATH = "hanbridge_logo.png"
32
  CLARE_LOGO_PATH = "clare_mascot.png"
33
+ CLARE_RUN_PATH = "Clare_Run.png"
34
+
35
+ # ================== 【核心修改】Base64 图片转换函数 ==================
36
+ def image_to_base64(image_path):
37
+ """将本地图片转换为 Base64 字符串,直接嵌入 HTML,避免路径错误"""
38
+ if not os.path.exists(image_path):
39
+ return "" # 如果文件不存在,返回空
40
+ with open(image_path, "rb") as img_file:
41
+ encoded_string = base64.b64encode(img_file.read()).decode('utf-8')
42
+ # 根据文件扩展名决定 MIME type
43
+ if image_path.lower().endswith(".png"):
44
+ mime = "image/png"
45
+ elif image_path.lower().endswith(".jpg") or image_path.lower().endswith(".jpeg"):
46
+ mime = "image/jpeg"
47
+ else:
48
+ mime = "image/png"
49
+ return f"data:{mime};base64,{encoded_string}"
50
 
51
  # ================== CSS (样式调整) ==================
52
  CUSTOM_CSS = """
 
60
  border-bottom: 2px solid #f3f4f6;
61
  margin-bottom: 15px;
62
  }
63
+
64
  /* User Guide 链接样式 */
65
  #user-guide-links button {
66
  background: transparent !important; border: none !important; box-shadow: none !important;
 
68
  color: #004a99 !important; text-decoration: underline; font-size: 0.8rem;
69
  }
70
  #user-guide-links button:hover { color: #002b66 !important; }
71
+
72
  /* Memory Line 区域样式 */
73
  .memory-line-box {
74
  border: 1px solid #e5e7eb;
75
  padding: 12px;
76
  border-radius: 8px;
77
  background-color: #f9fafb;
78
+ height: 100%;
79
  }
80
  """
81
 
 
106
  cognitive_state_state = gr.State({"confusion": 0, "mastery": 0})
107
  rag_chunks_state = gr.State([])
108
 
109
+ # ============ 1. 顶部 Header (使用 Base64 嵌入图片) ============
 
110
  gr.HTML(
111
  f"""
112
  <div class="header-container">
113
  <div style="display:flex; align-items:center; gap: 20px;">
114
+ <img src="{image_to_base64(CLARE_LOGO_PATH)}" style="height: 75px; object-fit: contain;">
115
  <div style="display:flex; flex-direction:column;">
116
  <div style="font-size: 32px; font-weight: 800; line-height: 1.1; color: #000;">
117
  Clare
 
122
  </div>
123
  </div>
124
  </div>
125
+
126
  <div style="text-align: right;">
127
+ <img src="{image_to_base64(HANBRIDGE_LOGO_PATH)}" style="height: 55px; object-fit: contain; margin-bottom: 5px;">
128
  <div style="font-size: 12px; color: #666;">
129
  🎓 (Student Name) (Student Email/ID)
130
  </div>
 
133
  """
134
  )
135
 
136
+ # ============ 2. 主体分栏布局 ============
137
  with gr.Row():
138
 
139
  # ============ [左侧] 控制面板 Sidebar ============
140
  with gr.Column(scale=1, min_width=200):
 
141
  clear_btn = gr.Button("Reset Conversation", variant="stop")
142
 
143
  gr.Markdown("### Model Settings")
 
169
  # ============ [中间] 主内容区 Center Main ============
170
  with gr.Column(scale=3):
171
 
172
+ # 上半部分:上传区 + Memory Line
173
  with gr.Row():
174
  # --- Upload File ---
175
  with gr.Column(scale=1):
 
186
  container=False
187
  )
188
 
189
+ # --- Memory Line (使用 Base64 嵌入奔跑图片) ---
190
  with gr.Column(scale=1):
 
191
  gr.HTML(
192
  f"""
193
  <div class="memory-line-box">
 
198
  <div style="position: relative; height: 35px; margin-top: 15px; margin-bottom: 5px;">
199
  <div style="position: absolute; bottom: 5px; left: 0; width: 100%; height: 8px; background-color: #e5e7eb; border-radius: 4px;"></div>
200
  <div style="position: absolute; bottom: 5px; left: 0; width: 40%; height: 8px; background-color: #8B1A1A; border-radius: 4px 0 0 4px;"></div>
201
+ <img src="{image_to_base64(CLARE_RUN_PATH)}" style="position: absolute; left: 36%; bottom: 8px; height: 35px; z-index: 10;">
202
  </div>
203
+
204
  <div style="display:flex; justify-content:space-between; align-items:center; margin-top:8px;">
205
  <div style="font-size: 12px; color: #666;">Next Review: T+7</div>
206
  <div style="font-size: 12px; color: #004a99; text-decoration:underline; cursor:pointer;">
 
210
  </div>
211
  """
212
  )
 
213
  review_btn = gr.Button("Review Now", size="sm", variant="primary")
 
 
214
  session_status = gr.Markdown(visible=False)
215
 
216
  # --- Chat Interface ---
 
226
  chatbot = gr.Chatbot(
227
  label="",
228
  height=450,
229
+ # 聊天框内的头像也可以使用 Base64,但 Gradio 的 avatar_images
230
+ # 通常直接接受路径即可(因为它内部会处理)。
231
+ # 如果这里头像也不显示,请告诉我,我再改这里。目前保持路径。
232
+ avatar_images=(None, CLARE_LOGO_PATH),
233
  show_label=False,
234
  bubble_full_width=False
235
  )
 
245
  # ============ [右侧] 功能栏 Right Sidebar ============
246
  with gr.Column(scale=1, min_width=180):
247
  gr.Markdown("### Actions")
 
248
  export_btn = gr.Button("Export Conversation", size="sm")
249
  quiz_btn = gr.Button("Let's Try (Micro-Quiz)", size="sm")
250
  summary_btn = gr.Button("Summarization", size="sm")
 
257
  show_label=False
258
  )
259
 
260
+ # ================== Logic Bindings (逻辑部分保持不变) ==================
261
 
 
262
  def update_course_and_rag(file, doc_type_val):
263
  topics = extract_course_topics_from_file(file, doc_type_val)
264
  rag_chunks = build_rag_chunks_from_file(file, doc_type_val)
 
271
  outputs=[course_outline_state, rag_chunks_state, session_status],
272
  )
273
 
 
274
  def respond(message, chat_history, course_outline, weaknesses, cognitive_state, rag_chunks, model, lang, mode, doc_type_val):
275
  resolved_lang = detect_language(message or "", lang)
276
 
 
303
  [user_input, chatbot, weakness_state, cognitive_state_state, session_status]
304
  )
305
 
 
306
  def on_export(chat_history, course_outline, mode, weaknesses, cognitive_state):
307
  return export_conversation(chat_history, course_outline, mode, weaknesses, cognitive_state)
308
 
 
330
  [result_display]
331
  )
332
 
 
333
  def clear_all():
334
  empty_state = {"confusion": 0, "mastery": 0}
335
  default_status = render_session_status("Concept Explainer", [], empty_state)
 
342
  queue=False
343
  )
344
 
 
345
  def show_guide(section):
346
  return get_user_guide_section(section)
347
 
 
351
  ug_memory_line.click(lambda: show_guide("memory_line"), outputs=result_display)
352
 
353
  if __name__ == "__main__":
354
+ # 移除 allowed_paths,因为 Base64 不需要它
355
  demo.launch()