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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -82
app.py CHANGED
@@ -28,7 +28,6 @@ from rag_engine import (
28
  from syllabus_utils import extract_course_topics_from_file
29
 
30
  # ================== Assets ==================
31
- # 根据你的截图文件名配置
32
  HANBRIDGE_LOGO_PATH = "hanbridge_logo.png"
33
  CLARE_LOGO_PATH = "clare_mascot.png"
34
  CLARE_RUN_PATH = "Clare_Run.png"
@@ -61,7 +60,7 @@ USER_GUIDE_SECTIONS = {
61
  "faq": "## FAQ\n\n**Q: Does Clare give assignment answers?** No..."
62
  }
63
 
64
- # ================== CSS (悬停提示 Tooltip 样式) ==================
65
  CUSTOM_CSS = """
66
  /* Header */
67
  .header-container {
@@ -70,76 +69,70 @@ CUSTOM_CSS = """
70
  border-bottom: 2px solid #f3f4f6; margin-bottom: 15px;
71
  }
72
 
73
- /* User Guide Accordion */
74
- .user-guide-item { margin-bottom: 5px; }
75
-
76
- /* Memory Line Box */
77
- .memory-line-box {
78
- border: 1px solid #e5e7eb; padding: 12px; border-radius: 8px;
79
- background-color: #f9fafb; height: 100%;
80
- display: flex; flex-direction: column; justify-content: space-between;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  }
82
 
83
- /* === CSS Tooltip Logic (纯 CSS 实现悬停提示) ===
84
- 应用于 Buttons (.action-btn) 和 HTML 元素 (.html-tooltip)
85
- */
86
-
87
- /* 1. 针对 Gradio 按钮的 Tooltip */
88
  .action-btn {
89
- position: relative;
90
- overflow: visible !important; /* 允许提示框超出按钮边界 */
 
 
91
  }
 
 
92
  .action-btn:hover::before {
93
- content: "See User Guide for details"; /* 提示文字 */
94
- position: absolute;
95
- bottom: 110%; /* 显示在按钮上方 */
96
- left: 50%;
97
- transform: translateX(-50%);
98
- background-color: #333;
99
- color: #fff;
100
- padding: 5px 10px;
101
- border-radius: 5px;
102
- font-size: 12px;
103
- white-space: nowrap;
104
- z-index: 1000;
105
- pointer-events: none;
106
- box-shadow: 0 2px 5px rgba(0,0,0,0.2);
107
- opacity: 0;
108
- animation: fadeIn 0.2s forwards;
109
  }
110
- /* 小三角箭头 */
111
  .action-btn:hover::after {
112
- content: "";
113
- position: absolute;
114
- bottom: 100%;
115
- left: 50%;
116
- margin-left: -5px;
117
- border-width: 5px;
118
- border-style: solid;
119
- border-color: #333 transparent transparent transparent;
120
- opacity: 0;
121
- animation: fadeIn 0.2s forwards;
122
  }
123
 
124
- /* 2. 针对 HTML 文本的 Tooltip (Memory Line Title) */
125
  .html-tooltip {
126
- border-bottom: 1px dashed #999; /* 虚线表示可悬停 */
127
- cursor: help;
128
- position: relative;
129
  }
130
  .html-tooltip:hover::before {
131
  content: attr(data-tooltip);
132
- position: absolute;
133
- bottom: 120%;
134
- left: 0;
135
- background-color: #333;
136
- color: #fff;
137
- padding: 5px 8px;
138
- border-radius: 4px;
139
- font-size: 11px;
140
- white-space: nowrap;
141
- z-index: 100;
142
- pointer-events: none;
143
  }
144
 
145
  @keyframes fadeIn { to { opacity: 1; } }
@@ -190,10 +183,10 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
190
 
191
  # Model Settings
192
  gr.Markdown("### Model Settings")
193
- model_name = gr.Textbox(label="Model", value=DEFAULT_MODEL, lines=1)
 
194
  language_preference = gr.Radio(choices=["Auto", "English", "简体中文"], value="Auto", label="Language")
195
 
196
- # Learning Mode (Use `info` for built-in hint)
197
  learning_mode = gr.Radio(
198
  choices=LEARNING_MODES,
199
  value="Concept Explainer",
@@ -201,66 +194,73 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
201
  info="See User Guide for mode definitions details."
202
  )
203
 
204
- # User Guide Accordion
205
- with gr.Accordion("User Guide", open=True):
206
- with gr.Accordion("Getting Started", open=False, elem_classes="user-guide-item"):
 
207
  gr.Markdown(USER_GUIDE_SECTIONS["getting_started"])
208
- with gr.Accordion("Mode Definition", open=False, elem_classes="user-guide-item"):
209
  gr.Markdown(USER_GUIDE_SECTIONS["mode_definition"])
210
- with gr.Accordion("How Clare Works", open=False, elem_classes="user-guide-item"):
211
  gr.Markdown(USER_GUIDE_SECTIONS["how_clare_works"])
212
- with gr.Accordion("What is Memory Line", open=False, elem_classes="user-guide-item"):
213
  gr.Markdown(USER_GUIDE_SECTIONS["memory_line"])
214
- with gr.Accordion("Learning Progress Report", open=False, elem_classes="user-guide-item"):
215
  gr.Markdown(USER_GUIDE_SECTIONS["learning_progress"])
216
- with gr.Accordion("How Clare Uses Your Files", open=False, elem_classes="user-guide-item"):
217
  gr.Markdown(USER_GUIDE_SECTIONS["how_files"])
218
- with gr.Accordion("Micro-Quiz", open=False, elem_classes="user-guide-item"):
219
  gr.Markdown(USER_GUIDE_SECTIONS["micro_quiz"])
220
- with gr.Accordion("Summarization", open=False, elem_classes="user-guide-item"):
221
  gr.Markdown(USER_GUIDE_SECTIONS["summarization"])
222
- with gr.Accordion("Export Conversation", open=False, elem_classes="user-guide-item"):
223
  gr.Markdown(USER_GUIDE_SECTIONS["export_conversation"])
224
- with gr.Accordion("FAQ", open=False, elem_classes="user-guide-item"):
225
  gr.Markdown(USER_GUIDE_SECTIONS["faq"])
226
 
227
- with gr.Group():
228
- gr.Button("System Settings", variant="secondary")
229
- gr.Button("Log Out", variant="secondary")
 
 
230
 
231
  # === [Center Main] ===
232
  with gr.Column(scale=3):
233
 
234
  # Upload & Memory Line
 
235
  with gr.Row():
236
  # Upload
237
  with gr.Column(scale=1):
238
- syllabus_file = gr.File(file_types=[".docx", ".pdf", ".pptx"], file_count="single", height=100, label="Upload File")
 
 
 
 
 
 
 
239
  doc_type = gr.Dropdown(choices=DOC_TYPES, value="Syllabus", label="File type", container=False)
240
 
241
  # Memory Line
242
  with gr.Column(scale=1):
243
  with gr.Group(elem_classes="memory-line-box"):
244
- # 使用 HTML class 实现悬停提示
245
  gr.HTML(
246
  f"""
247
  <div style="font-weight:bold; font-size:14px; margin-bottom:5px;">
248
  <span class="html-tooltip" data-tooltip="See User Guide for explanation">Memory Line</span>
249
  </div>
250
-
251
  <div style="position: relative; height: 35px; margin-top: 10px; margin-bottom: 5px;">
252
  <div style="position: absolute; bottom: 5px; left: 0; width: 100%; height: 8px; background-color: #e5e7eb; border-radius: 4px;"></div>
253
  <div style="position: absolute; bottom: 5px; left: 0; width: 40%; height: 8px; background-color: #8B1A1A; border-radius: 4px 0 0 4px;"></div>
254
  <img src="{image_to_base64(CLARE_RUN_PATH)}" style="position: absolute; left: 36%; bottom: 8px; height: 35px; z-index: 10;">
255
  </div>
256
-
257
  <div style="display:flex; justify-content:space-between; align-items:center;">
258
  <div style="font-size: 12px; color: #666;">Next Review: T+7</div>
259
  <div style="font-size: 12px; color: #004a99; text-decoration:underline; cursor:pointer;">Report ⬇️</div>
260
  </div>
261
  """
262
  )
263
- # Review Button
264
  review_btn = gr.Button("Review Now", size="sm", variant="primary")
265
  session_status = gr.Markdown(visible=False)
266
 
@@ -278,9 +278,15 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
278
 
279
  # === [Right Sidebar] ===
280
  with gr.Column(scale=1, min_width=180):
 
 
 
 
 
 
281
  gr.Markdown("### Actions")
282
 
283
- # Action Buttons: 使用 elem_classes="action-btn" 来激活 CSS Tooltip
284
  export_btn = gr.Button("Export Conversation", size="sm", elem_classes="action-btn")
285
  quiz_btn = gr.Button("Let's Try (Micro-Quiz)", size="sm", elem_classes="action-btn")
286
  summary_btn = gr.Button("Summarization", size="sm", elem_classes="action-btn")
 
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"
 
60
  "faq": "## FAQ\n\n**Q: Does Clare give assignment answers?** No..."
61
  }
62
 
63
+ # ================== CSS 样式表 ==================
64
  CUSTOM_CSS = """
65
  /* Header */
66
  .header-container {
 
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; } }
 
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
 
 
190
  learning_mode = gr.Radio(
191
  choices=LEARNING_MODES,
192
  value="Concept Explainer",
 
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(
249
  f"""
250
  <div style="font-weight:bold; font-size:14px; margin-bottom:5px;">
251
  <span class="html-tooltip" data-tooltip="See User Guide for explanation">Memory Line</span>
252
  </div>
 
253
  <div style="position: relative; height: 35px; margin-top: 10px; margin-bottom: 5px;">
254
  <div style="position: absolute; bottom: 5px; left: 0; width: 100%; height: 8px; background-color: #e5e7eb; border-radius: 4px;"></div>
255
  <div style="position: absolute; bottom: 5px; left: 0; width: 40%; height: 8px; background-color: #8B1A1A; border-radius: 4px 0 0 4px;"></div>
256
  <img src="{image_to_base64(CLARE_RUN_PATH)}" style="position: absolute; left: 36%; bottom: 8px; height: 35px; z-index: 10;">
257
  </div>
 
258
  <div style="display:flex; justify-content:space-between; align-items:center;">
259
  <div style="font-size: 12px; color: #666;">Next Review: T+7</div>
260
  <div style="font-size: 12px; color: #004a99; text-decoration:underline; cursor:pointer;">Report ⬇️</div>
261
  </div>
262
  """
263
  )
 
264
  review_btn = gr.Button("Review Now", size="sm", variant="primary")
265
  session_status = gr.Markdown(visible=False)
266
 
 
278
 
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")