SarahXia0405 commited on
Commit
1b7027d
·
verified ·
1 Parent(s): 3a40f53

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +115 -241
app.py CHANGED
@@ -27,12 +27,12 @@ from rag_engine import (
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
  if not os.path.exists(image_path):
38
  return ""
@@ -48,150 +48,19 @@ def image_to_base64(image_path):
48
 
49
  # ================== User Guide Content ==================
50
  USER_GUIDE_SECTIONS = {
51
- "getting_started": """
52
- ## Getting started
53
-
54
- Welcome to **Clare Your Personalized AI Tutor**.
55
-
56
- Clare is designed to support your learning through:
57
- - Clear explanations of course concepts
58
- - Socratic-style reasoning guidance
59
- - Personalized reinforcement based on learning science
60
- - Course-aligned answers using your uploaded materials
61
- - Micro-quizzes & summaries to strengthen understanding
62
-
63
- **To begin:**
64
- 1. Select your **Learning Mode** on the left
65
- 2. (Optional) Upload your **syllabus / slides / notes** at the top
66
- 3. Ask Clare any question about your course, assignment, or study plan.
67
- """,
68
- "mode_definition": """
69
- ## Mode Definition
70
-
71
- Clare offers different teaching modes to match how you prefer to learn.
72
-
73
- ### Concept Explainer
74
- Clear, structured explanations with examples — ideal for learning new topics.
75
-
76
- ### Socratic Tutor
77
- Clare asks guiding questions instead of giving direct answers.
78
- Helps you build reasoning and problem-solving skills.
79
-
80
- ### Exam Prep / Quiz
81
- Generates short practice questions aligned with your course week.
82
- Useful for self-testing and preparing for exams.
83
-
84
- ### Assignment Helper
85
- Helps you interpret assignment prompts, plan structure, and understand requirements.
86
- ❗ Clare does **not** produce full assignment answers (academic integrity).
87
-
88
- ### Quick Summary
89
- Gives brief summaries of slides, reading materials, or long questions.
90
- """,
91
- "how_clare_works": """
92
- ## How Clare Works
93
-
94
- Clare combines **course context + learning science + AI reasoning** to generate answers.
95
-
96
- Clare uses:
97
- - **Your selected Learning Mode** Determines tone, depth, and interaction style.
98
-
99
- - **Your uploaded course files** Syllabus, slides, or papers help align answers with your specific course.
100
-
101
- - **Reinforcement learning cycle** Answers may prioritize key concepts you’re likely to forget (based on the forgetting curve).
102
-
103
- - **Adaptive explanation depth** Clare can adjust complexity depending on your previous interactions.
104
-
105
- - **Responsible AI principles** Avoids harmful output and preserves academic integrity.
106
- """,
107
- "memory_line": """
108
- ## What is Memory Line?
109
-
110
- **Memory Line** is a visualization of your *learning reinforcement cycle*.
111
-
112
- Based on the **forgetting-curve model**, Clare organizes your review topics into:
113
- - **T+0 (Current Week)** – new concepts
114
- - **T+7** – first spaced review
115
- - **T+14** – reinforcement review
116
- - **T+30** – long-term consolidation
117
-
118
- Clare uses these cycles to decide:
119
- - Which concepts to reinforce today
120
- - Which explanations to prioritize
121
- - When to introduce quick review questions
122
-
123
- **Review Now** will generate a small set of concepts that are due for spaced repetition.
124
- """,
125
- "learning_progress": """
126
- ## Learning Progress Report
127
-
128
- The Learning Progress Report highlights:
129
- - **Concepts mastered** - **Concepts in progress** - **Concepts due for review** - Your recent **micro-quiz results** - Suggested **next-step topics**
130
-
131
- You can download a **summary** at any time to use as study notes.
132
- """,
133
- "how_files": """
134
- ## How Clare Uses Your Files
135
-
136
- Your uploaded syllabus / slides / notes help Clare:
137
-
138
- - Align explanations with your exact course
139
- - Use terminology consistent with your professor
140
- - Improve factual accuracy
141
- - Generate personalized reinforcement content
142
- - 🔒 **Privacy**: Files are used only within your session.
143
-
144
- Accepted formats: **.docx / .pdf / .pptx**
145
- """,
146
- "micro_quiz": """
147
- ## Micro-Quiz
148
-
149
- The **Micro-Quiz** function provides a:
150
-
151
- - 1-minute self-check
152
- - 1–3 questions based on your recent topics
153
- - Instant feedback
154
-
155
- Micro-quizzes strengthen your memory and are part of Clare’s reinforcement system.
156
- """,
157
- "summarization": """
158
- ## Summarization
159
-
160
- Clare can summarize:
161
-
162
- - Lecture notes
163
- - Uploaded PDFs
164
- - Long conversation threads
165
- - Complex concepts
166
-
167
- Summary styles can include: Bullet points, Key ideas, Study notes, Comparison-style highlights.
168
- """,
169
- "export_conversation": """
170
- ## Export Conversation
171
-
172
- You can export your chat session for:
173
-
174
- - Study review
175
- - Exam preparation
176
- - Documentation for tutoring help
177
- - Saving important explanations
178
-
179
- Export format: **Markdown / plain text**.
180
- """,
181
- "faq": """
182
- ## FAQ
183
-
184
- **Q: Does Clare give assignment answers?** No. Clare assists with understanding and planning but does **not** generate full solutions.
185
-
186
- **Q: Does Clare replace lectures or TA office hours?** No. Clare supplements your learning by providing on-demand guidance.
187
-
188
- **Q: Can Clare explain my professor’s slides?** Yes — upload your slides so Clare can align explanations with your course.
189
-
190
- **Q: What languages does Clare support?** Currently: English & 简体中文.
191
- """
192
  }
193
 
194
- # ================== CSS ==================
195
  CUSTOM_CSS = """
196
  /* Header */
197
  .header-container {
@@ -200,25 +69,63 @@ CUSTOM_CSS = """
200
  border-bottom: 2px solid #f3f4f6; margin-bottom: 15px;
201
  }
202
 
203
- /* 问号按钮样式 (? Buttons) */
204
- .help-btn {
205
- min-width: 25px !important; width: 25px !important; height: 25px !important;
206
- padding: 0 !important; border-radius: 50% !important;
207
- font-size: 12px !important; font-weight: bold !important;
208
- background: transparent !important; color: #666 !important; border: 1px solid #ccc !important;
209
- box-shadow: none !important; margin-left: 5px !important;
210
- display: inline-flex !important; align-items: center !important; justify-content: center !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  }
212
- .help-btn:hover { background: #eee !important; color: #333 !important; border-color: #999 !important; }
213
 
214
- /* Memory Line */
215
  .memory-line-box {
216
  border: 1px solid #e5e7eb; padding: 12px; border-radius: 8px;
217
  background-color: #f9fafb; height: 100%;
 
218
  }
219
 
220
- /* User Guide Accordion specific tweaking */
221
- .user-guide-item { margin-bottom: 5px; }
 
 
 
 
222
  """
223
 
224
  # ================== Gradio App ==================
@@ -238,7 +145,7 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
238
  <div style="display:flex; align-items:center; gap: 20px;">
239
  <img src="{image_to_base64(CLARE_LOGO_PATH)}" style="height: 75px; object-fit: contain;">
240
  <div style="display:flex; flex-direction:column;">
241
- <div style="font-size: 32px; font-weight: 800; line-height: 1.1; color: #000;">
242
  Clare
243
  <span style="font-size: 18px; font-weight: 600; margin-left: 10px;">Your Personalized AI Tutor</span>
244
  </div>
@@ -267,55 +174,42 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
267
  # Model Settings
268
  gr.Markdown("### Model Settings")
269
  model_name = gr.Textbox(label="Model", value=DEFAULT_MODEL, lines=1)
270
- language_preference = gr.Radio(
271
- choices=["Auto", "English", "简体中文"],
272
- value="Auto",
273
- label="Language"
274
- )
275
 
276
- # Learning Mode with Help Button
277
- with gr.Row(variant="compact", elem_classes="no-gap"):
278
- gr.Markdown("**Learning Mode**")
279
- mode_help_btn = gr.Button("?", elem_classes="help-btn") # ? Button
280
 
281
  learning_mode = gr.Radio(
282
  choices=LEARNING_MODES,
283
  value="Concept Explainer",
284
- label=None, # Hide default label to use custom header above
285
- info="Select style",
286
- show_label=False
287
  )
288
 
289
- # --- User Guide (New Design: Nested Accordions) ---
290
  with gr.Accordion("User Guide", open=True):
291
- # 这里实现了“点击一个展开一个”的效果
292
  with gr.Accordion("Getting Started", open=False, elem_classes="user-guide-item"):
293
  gr.Markdown(USER_GUIDE_SECTIONS["getting_started"])
294
-
295
  with gr.Accordion("Mode Definition", open=False, elem_classes="user-guide-item"):
296
  gr.Markdown(USER_GUIDE_SECTIONS["mode_definition"])
297
-
298
  with gr.Accordion("How Clare Works", open=False, elem_classes="user-guide-item"):
299
  gr.Markdown(USER_GUIDE_SECTIONS["how_clare_works"])
300
-
301
  with gr.Accordion("What is Memory Line", open=False, elem_classes="user-guide-item"):
302
  gr.Markdown(USER_GUIDE_SECTIONS["memory_line"])
303
-
304
  with gr.Accordion("Learning Progress Report", open=False, elem_classes="user-guide-item"):
305
  gr.Markdown(USER_GUIDE_SECTIONS["learning_progress"])
306
-
307
  with gr.Accordion("How Clare Uses Your Files", open=False, elem_classes="user-guide-item"):
308
  gr.Markdown(USER_GUIDE_SECTIONS["how_files"])
309
-
310
  with gr.Accordion("Micro-Quiz", open=False, elem_classes="user-guide-item"):
311
  gr.Markdown(USER_GUIDE_SECTIONS["micro_quiz"])
312
-
313
  with gr.Accordion("Summarization", open=False, elem_classes="user-guide-item"):
314
  gr.Markdown(USER_GUIDE_SECTIONS["summarization"])
315
-
316
  with gr.Accordion("Export Conversation", open=False, elem_classes="user-guide-item"):
317
  gr.Markdown(USER_GUIDE_SECTIONS["export_conversation"])
318
-
319
  with gr.Accordion("FAQ", open=False, elem_classes="user-guide-item"):
320
  gr.Markdown(USER_GUIDE_SECTIONS["faq"])
321
 
@@ -330,48 +224,38 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
330
  with gr.Row():
331
  # Upload
332
  with gr.Column(scale=1):
333
- with gr.Row():
334
- gr.Markdown("**Upload Course File**")
335
- file_help_btn = gr.Button("?", elem_classes="help-btn") # ? Button
336
 
337
- syllabus_file = gr.File(
338
- file_types=[".docx", ".pdf", ".pptx"],
339
- file_count="single",
340
- height=100,
341
- show_label=False
342
- )
343
- doc_type = gr.Dropdown(
344
- choices=DOC_TYPES,
345
- value="Syllabus",
346
- label="File type",
347
- container=False
348
- )
349
 
350
  # Memory Line
351
  with gr.Column(scale=1):
352
- gr.HTML(
353
- f"""
354
- <div class="memory-line-box">
355
- <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:5px;">
356
- <div style="font-weight:bold; font-size:14px;">Memory Line</div>
357
- </div>
358
- <div style="position: relative; height: 35px; margin-top: 15px; margin-bottom: 5px;">
 
 
 
359
  <div style="position: absolute; bottom: 5px; left: 0; width: 100%; height: 8px; background-color: #e5e7eb; border-radius: 4px;"></div>
360
  <div style="position: absolute; bottom: 5px; left: 0; width: 40%; height: 8px; background-color: #8B1A1A; border-radius: 4px 0 0 4px;"></div>
361
  <img src="{image_to_base64(CLARE_RUN_PATH)}" style="position: absolute; left: 36%; bottom: 8px; height: 35px; z-index: 10;">
362
  </div>
363
- <div style="display:flex; justify-content:space-between; align-items:center; margin-top:8px;">
364
  <div style="font-size: 12px; color: #666;">Next Review: T+7</div>
365
- <div style="font-size: 12px; color: #004a99; text-decoration:underline;">Learning Progress Report ⬇️</div>
366
  </div>
367
- </div>
368
- """
369
- )
370
- # Memory Line 的问号按钮 (放在 HTML 下方紧凑的一行里)
371
- with gr.Row(elem_classes="no-gap"):
372
- ml_help_btn = gr.Button("What is Memory Line?", size="sm", variant="secondary")
373
- review_btn = gr.Button("Review Now", size="sm", variant="primary")
374
- session_status = gr.Markdown(visible=False)
375
 
376
  # Chat
377
  gr.Markdown(
@@ -382,41 +266,33 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
382
  </div>
383
  """
384
  )
385
- chatbot = gr.Chatbot(
386
- label="", height=450,
387
- avatar_images=(None, CLARE_LOGO_PATH),
388
- show_label=False, bubble_full_width=False
389
- )
390
- user_input = gr.Textbox(
391
- label="Your Input", placeholder="Ask about a concept, your assignment, or let Clare test you...",
392
- show_label=False, container=True, autofocus=True
393
- )
394
 
395
  # === [Right Sidebar] ===
396
  with gr.Column(scale=1, min_width=180):
397
  gr.Markdown("### Actions")
398
 
399
- with gr.Row():
400
- export_btn = gr.Button("Export Conversation", size="sm", scale=4)
401
- export_help_btn = gr.Button("?", elem_classes="help-btn", scale=1)
 
402
 
403
- with gr.Row():
404
- quiz_btn = gr.Button("Let's Try (Micro-Quiz)", size="sm", scale=4)
405
- quiz_help_btn = gr.Button("?", elem_classes="help-btn", scale=1)
406
-
407
- with gr.Row():
408
- summary_btn = gr.Button("Summarization", size="sm", scale=4)
409
- summary_help_btn = gr.Button("?", elem_classes="help-btn", scale=1)
 
 
410
 
411
  gr.Markdown("### Results")
412
- result_display = gr.Textbox(
413
- label="Generated Content", lines=15,
414
- placeholder="Results from Export, Quiz, or Summary will appear here...",
415
- show_label=False
416
- )
417
 
418
- # ================== 问号按钮逻辑 (Pop-up Info) ==================
419
- # 当点击问号时,弹出对应的信息
420
  mode_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["mode_definition"], title="Mode Definition"))
421
  file_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["how_files"], title="How Files Work"))
422
  ml_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["memory_line"], title="Memory Line"))
@@ -424,7 +300,7 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
424
  quiz_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["micro_quiz"], title="Micro-Quiz"))
425
  summary_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["summarization"], title="Summarization"))
426
 
427
- # ================== Main Logic (保持原有逻辑) ==================
428
  def update_course_and_rag(file, doc_type_val):
429
  topics = extract_course_topics_from_file(file, doc_type_val)
430
  rag_chunks = build_rag_chunks_from_file(file, doc_type_val)
@@ -446,12 +322,10 @@ with gr.Blocks(title="Clare – Hanbridge AI Teaching Assistant", css=CUSTOM_CSS
446
 
447
  user_input.submit(respond, [user_input, chatbot, course_outline_state, weakness_state, cognitive_state_state, rag_chunks_state, model_name, language_preference, learning_mode, doc_type], [user_input, chatbot, weakness_state, cognitive_state_state, session_status])
448
 
449
- # Button Actions
450
  export_btn.click(lambda h, c, m, w, cog: export_conversation(h, c, m, w, cog), [chatbot, course_outline_state, learning_mode, weakness_state, cognitive_state_state], [result_display])
451
  quiz_btn.click(lambda h, c, w, cog, m, l: generate_quiz_from_history(h, c, w, cog, m, l), [chatbot, course_outline_state, weakness_state, cognitive_state_state, model_name, language_preference], [result_display])
452
  summary_btn.click(lambda h, c, w, cog, m, l: summarize_conversation(h, c, w, cog, m, l), [chatbot, course_outline_state, weakness_state, cognitive_state_state, model_name, language_preference], [result_display])
453
 
454
- # Reset
455
  def clear_all():
456
  empty_state = {"confusion": 0, "mastery": 0}
457
  default_status = render_session_status("Concept Explainer", [], empty_state)
 
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 Helper ==================
36
  def image_to_base64(image_path):
37
  if not os.path.exists(image_path):
38
  return ""
 
48
 
49
  # ================== User Guide Content ==================
50
  USER_GUIDE_SECTIONS = {
51
+ "getting_started": "## Getting started\n\nWelcome to **Clare**...",
52
+ "mode_definition": "## Mode Definition\n\nClare offers different teaching modes...",
53
+ "how_clare_works": "## How Clare Works\n\nClare combines course context...",
54
+ "memory_line": "## What is Memory Line?\n\n**Memory Line** is a visualization of your *learning reinforcement cycle*...",
55
+ "learning_progress": "## Learning Progress Report\n\nThe Learning Progress Report highlights...",
56
+ "how_files": "## How Clare Uses Your Files\n\nYour uploaded syllabus / slides / notes help Clare...",
57
+ "micro_quiz": "## Micro-Quiz\n\nThe **Micro-Quiz** function provides a 1-minute self-check...",
58
+ "summarization": "## Summarization\n\nClare can summarize lecture notes, PDFs, etc...",
59
+ "export_conversation": "## Export Conversation\n\nYou can export your chat session for study review...",
60
+ "faq": "## FAQ\n\n**Q: Does Clare give assignment answers?** No..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
 
63
+ # ================== CSS (Trademark Style) ==================
64
  CUSTOM_CSS = """
65
  /* Header */
66
  .header-container {
 
69
  border-bottom: 2px solid #f3f4f6; margin-bottom: 15px;
70
  }
71
 
72
+ /* User Guide Accordion */
73
+ .user-guide-item { margin-bottom: 5px; }
74
+
75
+ /* === Trademark Style Question Mark Buttons === */
76
+ .tm-help-btn {
77
+ display: inline-block !important;
78
+ background: transparent !important;
79
+ border: none !important;
80
+ box-shadow: none !important;
81
+ padding: 0 !important;
82
+ color: #9ca3af !important; /* Light Grey */
83
+ font-size: 14px !important; /* Small font */
84
+ line-height: 1 !important;
85
+ min-width: auto !important;
86
+ width: 20px !important;
87
+ height: 20px !important;
88
+ margin-top: -8px !important; /* Lift up like superscript */
89
+ margin-left: 0px !important;
90
+ cursor: pointer !important;
91
+ vertical-align: top !important;
92
+ z-index: 10;
93
+ }
94
+ .tm-help-btn:hover {
95
+ color: #4b5563 !important; /* Darker grey on hover */
96
+ transform: scale(1.1);
97
+ }
98
+
99
+ /* Container to hold Text + TM-Button tightly */
100
+ .label-row {
101
+ display: flex !important;
102
+ align-items: center !important;
103
+ gap: 0px !important; /* No gap between text and ? */
104
+ margin-bottom: 5px !important;
105
+ width: fit-content !important;
106
+ }
107
+
108
+ /* Remove default Markdown margins for tight layout */
109
+ .tight-label p {
110
+ margin: 0 !important;
111
+ font-weight: bold;
112
+ font-size: 1rem;
113
+ line-height: 1.2;
114
  }
 
115
 
116
+ /* Memory Line Box */
117
  .memory-line-box {
118
  border: 1px solid #e5e7eb; padding: 12px; border-radius: 8px;
119
  background-color: #f9fafb; height: 100%;
120
+ display: flex; flex-direction: column; justify-content: space-between;
121
  }
122
 
123
+ /* Action Buttons Row */
124
+ .action-row {
125
+ display: flex !important;
126
+ align-items: center !important;
127
+ margin-bottom: 5px !important;
128
+ }
129
  """
130
 
131
  # ================== Gradio App ==================
 
145
  <div style="display:flex; align-items:center; gap: 20px;">
146
  <img src="{image_to_base64(CLARE_LOGO_PATH)}" style="height: 75px; object-fit: contain;">
147
  <div style="display:flex; flex-direction:column;">
148
+ <div style="font-size: 34px; font-weight: 800; line-height: 1.1; color: #000;">
149
  Clare
150
  <span style="font-size: 18px; font-weight: 600; margin-left: 10px;">Your Personalized AI Tutor</span>
151
  </div>
 
174
  # Model Settings
175
  gr.Markdown("### Model Settings")
176
  model_name = gr.Textbox(label="Model", value=DEFAULT_MODEL, lines=1)
177
+ language_preference = gr.Radio(choices=["Auto", "English", "简体中文"], value="Auto", label="Language")
 
 
 
 
178
 
179
+ # Learning Mode Title + Trademark (?)
180
+ with gr.Row(elem_classes="label-row"):
181
+ gr.Markdown("Learning Mode", elem_classes="tight-label")
182
+ mode_help_btn = gr.Button("?", elem_classes="tm-help-btn")
183
 
184
  learning_mode = gr.Radio(
185
  choices=LEARNING_MODES,
186
  value="Concept Explainer",
187
+ label=None,
188
+ show_label=False,
189
+ info="Select style"
190
  )
191
 
192
+ # User Guide Accordion
193
  with gr.Accordion("User Guide", open=True):
194
+ # Using lambda to defer content loading isn't necessary here, simple strings work
195
  with gr.Accordion("Getting Started", open=False, elem_classes="user-guide-item"):
196
  gr.Markdown(USER_GUIDE_SECTIONS["getting_started"])
 
197
  with gr.Accordion("Mode Definition", open=False, elem_classes="user-guide-item"):
198
  gr.Markdown(USER_GUIDE_SECTIONS["mode_definition"])
 
199
  with gr.Accordion("How Clare Works", open=False, elem_classes="user-guide-item"):
200
  gr.Markdown(USER_GUIDE_SECTIONS["how_clare_works"])
 
201
  with gr.Accordion("What is Memory Line", open=False, elem_classes="user-guide-item"):
202
  gr.Markdown(USER_GUIDE_SECTIONS["memory_line"])
 
203
  with gr.Accordion("Learning Progress Report", open=False, elem_classes="user-guide-item"):
204
  gr.Markdown(USER_GUIDE_SECTIONS["learning_progress"])
 
205
  with gr.Accordion("How Clare Uses Your Files", open=False, elem_classes="user-guide-item"):
206
  gr.Markdown(USER_GUIDE_SECTIONS["how_files"])
 
207
  with gr.Accordion("Micro-Quiz", open=False, elem_classes="user-guide-item"):
208
  gr.Markdown(USER_GUIDE_SECTIONS["micro_quiz"])
 
209
  with gr.Accordion("Summarization", open=False, elem_classes="user-guide-item"):
210
  gr.Markdown(USER_GUIDE_SECTIONS["summarization"])
 
211
  with gr.Accordion("Export Conversation", open=False, elem_classes="user-guide-item"):
212
  gr.Markdown(USER_GUIDE_SECTIONS["export_conversation"])
 
213
  with gr.Accordion("FAQ", open=False, elem_classes="user-guide-item"):
214
  gr.Markdown(USER_GUIDE_SECTIONS["faq"])
215
 
 
224
  with gr.Row():
225
  # Upload
226
  with gr.Column(scale=1):
227
+ with gr.Row(elem_classes="label-row"):
228
+ gr.Markdown("Upload Course File", elem_classes="tight-label")
229
+ file_help_btn = gr.Button("?", elem_classes="tm-help-btn") # Added help here too for consistency
230
 
231
+ syllabus_file = gr.File(file_types=[".docx", ".pdf", ".pptx"], file_count="single", height=100, show_label=False)
232
+ doc_type = gr.Dropdown(choices=DOC_TYPES, value="Syllabus", label="File type", container=False)
 
 
 
 
 
 
 
 
 
 
233
 
234
  # Memory Line
235
  with gr.Column(scale=1):
236
+ with gr.Group(elem_classes="memory-line-box"):
237
+ # Title Row (TM Style)
238
+ with gr.Row(elem_classes="label-row"):
239
+ gr.Markdown("Memory Line", elem_classes="tight-label")
240
+ ml_help_btn = gr.Button("?", elem_classes="tm-help-btn")
241
+
242
+ # Progress Bar HTML
243
+ gr.HTML(
244
+ f"""
245
+ <div style="position: relative; height: 35px; margin-top: 10px; margin-bottom: 5px;">
246
  <div style="position: absolute; bottom: 5px; left: 0; width: 100%; height: 8px; background-color: #e5e7eb; border-radius: 4px;"></div>
247
  <div style="position: absolute; bottom: 5px; left: 0; width: 40%; height: 8px; background-color: #8B1A1A; border-radius: 4px 0 0 4px;"></div>
248
  <img src="{image_to_base64(CLARE_RUN_PATH)}" style="position: absolute; left: 36%; bottom: 8px; height: 35px; z-index: 10;">
249
  </div>
250
+ <div style="display:flex; justify-content:space-between; align-items:center;">
251
  <div style="font-size: 12px; color: #666;">Next Review: T+7</div>
252
+ <div style="font-size: 12px; color: #004a99; text-decoration:underline; cursor:pointer;">Report ⬇️</div>
253
  </div>
254
+ """
255
+ )
256
+ # Review Button (Inside the box)
257
+ review_btn = gr.Button("Review Now", size="sm", variant="primary")
258
+ session_status = gr.Markdown(visible=False)
 
 
 
259
 
260
  # Chat
261
  gr.Markdown(
 
266
  </div>
267
  """
268
  )
269
+ chatbot = gr.Chatbot(label="", height=450, avatar_images=(None, CLARE_LOGO_PATH), show_label=False, bubble_full_width=False)
270
+ user_input = gr.Textbox(label="Your Input", placeholder="Ask about a concept, your assignment, or let Clare test you...", show_label=False, container=True, autofocus=True)
 
 
 
 
 
 
 
271
 
272
  # === [Right Sidebar] ===
273
  with gr.Column(scale=1, min_width=180):
274
  gr.Markdown("### Actions")
275
 
276
+ # Action: Export
277
+ with gr.Row(elem_classes="action-row", variant="compact"):
278
+ export_btn = gr.Button("Export Conversation", size="sm", scale=10)
279
+ export_help_btn = gr.Button("?", elem_classes="tm-help-btn", scale=1) # The TM button
280
 
281
+ # Action: Quiz
282
+ with gr.Row(elem_classes="action-row", variant="compact"):
283
+ quiz_btn = gr.Button("Let's Try (Micro-Quiz)", size="sm", scale=10)
284
+ quiz_help_btn = gr.Button("?", elem_classes="tm-help-btn", scale=1)
285
+
286
+ # Action: Summary
287
+ with gr.Row(elem_classes="action-row", variant="compact"):
288
+ summary_btn = gr.Button("Summarization", size="sm", scale=10)
289
+ summary_help_btn = gr.Button("?", elem_classes="tm-help-btn", scale=1)
290
 
291
  gr.Markdown("### Results")
292
+ result_display = gr.Textbox(label="Generated Content", lines=15, placeholder="Results...", show_label=False)
 
 
 
 
293
 
294
+ # ================== Logic Bindings ==================
295
+ # Help Buttons (Pop-ups)
296
  mode_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["mode_definition"], title="Mode Definition"))
297
  file_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["how_files"], title="How Files Work"))
298
  ml_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["memory_line"], title="Memory Line"))
 
300
  quiz_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["micro_quiz"], title="Micro-Quiz"))
301
  summary_help_btn.click(lambda: gr.Info(USER_GUIDE_SECTIONS["summarization"], title="Summarization"))
302
 
303
+ # Core Logic
304
  def update_course_and_rag(file, doc_type_val):
305
  topics = extract_course_topics_from_file(file, doc_type_val)
306
  rag_chunks = build_rag_chunks_from_file(file, doc_type_val)
 
322
 
323
  user_input.submit(respond, [user_input, chatbot, course_outline_state, weakness_state, cognitive_state_state, rag_chunks_state, model_name, language_preference, learning_mode, doc_type], [user_input, chatbot, weakness_state, cognitive_state_state, session_status])
324
 
 
325
  export_btn.click(lambda h, c, m, w, cog: export_conversation(h, c, m, w, cog), [chatbot, course_outline_state, learning_mode, weakness_state, cognitive_state_state], [result_display])
326
  quiz_btn.click(lambda h, c, w, cog, m, l: generate_quiz_from_history(h, c, w, cog, m, l), [chatbot, course_outline_state, weakness_state, cognitive_state_state, model_name, language_preference], [result_display])
327
  summary_btn.click(lambda h, c, w, cog, m, l: summarize_conversation(h, c, w, cog, m, l), [chatbot, course_outline_state, weakness_state, cognitive_state_state, model_name, language_preference], [result_display])
328
 
 
329
  def clear_all():
330
  empty_state = {"confusion": 0, "mastery": 0}
331
  default_status = render_session_status("Concept Explainer", [], empty_state)