jdesiree commited on
Commit
fe370ac
·
verified ·
1 Parent(s): 40ffd96

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -168
app.py CHANGED
@@ -76,24 +76,19 @@ You recognize that students may seek direct answers to homework, assignments, or
76
  - Encourage students to explain their thinking and reasoning
77
  - Provide honest, accurate feedback even when it may not be what the student wants to hear
78
 
79
- Your goal is to be an educational partner who empowers students to succeed through understanding, not a service that completes their work for them."""
 
80
 
81
- math_template = ChatPromptTemplate.from_messages([
82
- ("system", """{system_message}
83
- Math Mode
84
  LaTeX formatting is enabled for math. You must provide LaTeX formatting for all math, either as inline LaTeX or centered display LaTeX.
85
  You will address requests to solve, aid in understanding, or explore mathematical context. Use logical ordering for content, providing necessary terms and definitions as well as concept explanations along with math to foster understanding of core concepts. Rather than specifically answering the math problem provided, begin with solving a similar problem that requires the same steps and foundational mathematical knowledge, then prompt the user to work through the problem themselves. If the user insists you solve the problem, engage in a two-way conversation where you provide the steps but request the user solve for the answer one step at a time.
86
  LaTeX should always be used for math.
87
  LaTeX Examples:
88
  - Inline: "The slope is $m = \\frac{{y_2 - y_1}}{{x_2 - x_1}}$ in this case."
89
  - Display: "The quadratic formula is: $x = \\frac{{-b \\pm \\sqrt{{b^2-4ac}}}}{{2a}}$"
90
- Always use double backslashes (\\\\) for LaTeX commands like \\\\frac, \\\\sqrt, \\\\int, etc."""),
91
- ("human", "{question}")
92
- ])
93
 
94
- research_template = ChatPromptTemplate.from_messages([
95
- ("system", """{system_message}
96
- Research Mode
97
  Your main goal is to help the user learn to research topics, a critical skill. Function as a partner rather than a search engine.
98
  Over the course of the conversation, guide the user through a seven-step research process:
99
  1) **Identifying a topic**
@@ -120,127 +115,23 @@ Reference: Smith, J.A. (2023) Book title. Publisher.
120
  IEEE Style
121
  In-text: [1]
122
  Reference: [1] J. A. Smith, Book Title. Publisher, 2023.
123
- In this mode you may not use LaTeX formatting."""),
124
- ("human", "{question}")
125
- ])
126
 
127
- study_template = ChatPromptTemplate.from_messages([
128
- ("system", """{system_message}
129
- Study Mode
130
  Engage the user in a mix of two teaching styles: student-centered and inquiry-based learning.
131
  Student Centered: Adjust to reflect the student's reading level and level of understanding of a topic as the conversation progresses. Do not assume the user is an expert but instead assume they may have familiarity but desire to learn more about the topic they are studying. Provide definitions for terms you use in a conversational way, gradually shifting to using just the terms without definitions as the user becomes more familiar with them.
132
  Inquiry-based learning: Engage the user through questions that compel them to consider what they want to know and then explore the topics through guided conversation.
133
  Over the course of the conversation, prompt the user with a question to gauge their growing knowledge or progress on the topic.
134
  For example:
135
  After two to three turns of conversation discussing a topic, pick a specific term or concept from the conversation history to craft either a multiple-choice or written answer question for the user with no other comments along with it. If the student is correct, congratulate them on their progress and inquire about their next learning goal on the topic. If the user fails the question, return with a short response that explains the correct answer in a kind tone.
136
- In this mode you may not use LaTeX formatting."""),
137
- ("human", "{question}")
138
- ])
 
139
 
140
- general_template = ChatPromptTemplate.from_messages([
141
- ("system", """{system_message}
142
- General Mode
143
- You are EduBot, a comprehensive AI learning assistant. Help users leverage educational tools and resources to enrich their education. Offer yourself as a resource for the student, prompting them to request help with **math topics**, **research strategy**, or **studying a topic**."""),
144
- ("human", "{question}")
145
- ])
146
 
147
  # --- Core Logic Functions ---
148
- def detect_subject(message, history=None):
149
- """
150
- Detects the subject of the user's message based on keywords and conversation context.
151
-
152
- Args:
153
- message (str): Current user message
154
- history (list): Chat history with role/content structure
155
-
156
- Returns:
157
- tuple: (template, mode_string)
158
- """
159
- message_lower = message.lower()
160
-
161
- math_keywords = ['math', 'mathematics', 'solve', 'calculate', 'equation', 'formula', 'algebra', 'geometry', 'calculus', 'derivative', 'integral', 'theorem', 'proof', 'trigonometry', 'statistics', 'probability', 'arithmetic', 'fraction', 'decimal', 'percentage', 'graph', 'function', 'polynomial', 'logarithm', 'exponential', 'matrix', 'vector', 'limit', 'differential', 'optimization', 'summation']
162
-
163
- research_keywords = ['research', 'source', 'sources', 'citation', 'cite', 'bibliography', 'reference', 'references', 'academic', 'scholarly', 'paper', 'essay', 'thesis', 'dissertation', 'database', 'journal', 'article', 'peer review', 'literature review', 'methodology', 'analysis', 'findings', 'conclusion', 'abstract', 'hypothesis', 'data collection', 'survey', 'interview', 'experiment']
164
-
165
- study_keywords = ['study', 'studying', 'memorize', 'memory', 'exam', 'test', 'testing', 'quiz', 'quizzing', 'review', 'reviewing', 'learn', 'learning', 'remember', 'recall', 'focus', 'concentration', 'motivation', 'notes', 'note-taking', 'flashcard', 'flashcards', 'comprehension', 'understanding', 'retention', 'practice', 'drill', 'preparation', 'revision', 'cramming']
166
-
167
- # Score the current message
168
- current_scores = {
169
- 'math': sum(1 for keyword in math_keywords if keyword in message_lower),
170
- 'research': sum(1 for keyword in research_keywords if keyword in message_lower),
171
- 'study': sum(1 for keyword in study_keywords if keyword in message_lower)
172
- }
173
-
174
- # Analyze recent conversation history for context
175
- context_scores = {'math': 0, 'research': 0, 'study': 0}
176
- last_mode = None
177
-
178
- if history:
179
- # Look at last 3-5 exchanges for context
180
- recent_history = history[-6:] # Last 3 user-bot exchanges
181
-
182
- for i, exchange in enumerate(recent_history):
183
- if exchange.get("role") == "user":
184
- content_lower = exchange.get("content", "").lower()
185
-
186
- # Weight recent messages more heavily
187
- weight = 0.5 - (i * 0.1) # More recent = higher weight
188
- if weight < 0.1:
189
- weight = 0.1
190
-
191
- context_scores['math'] += weight * sum(1 for keyword in math_keywords if keyword in content_lower)
192
- context_scores['research'] += weight * sum(1 for keyword in research_keywords if keyword in content_lower)
193
- context_scores['study'] += weight * sum(1 for keyword in study_keywords if keyword in content_lower)
194
-
195
- # Check if bot responses indicate a specific mode
196
- elif exchange.get("role") == "assistant":
197
- content = exchange.get("content", "")
198
- if "*Math Mode*" in content:
199
- last_mode = 'math'
200
- elif "*Research Mode*" in content:
201
- last_mode = 'research'
202
- elif "*Study Mode*" in content:
203
- last_mode = 'study'
204
-
205
- # Combine current message scores with context
206
- final_scores = {
207
- 'math': current_scores['math'] * 2.0 + context_scores['math'], # Current message weighted more
208
- 'research': current_scores['research'] * 2.0 + context_scores['research'],
209
- 'study': current_scores['study'] * 2.0 + context_scores['study']
210
- }
211
-
212
- # Add bonus for continuing in the same mode (conversation persistence)
213
- if last_mode and last_mode in final_scores:
214
- final_scores[last_mode] += 0.5
215
-
216
- # Handle ambiguous/continuation messages
217
- ambiguous_phrases = ['next', 'continue', 'more', 'explain', 'help', 'what about', 'can you', 'how do', 'show me']
218
- is_ambiguous = any(phrase in message_lower for phrase in ambiguous_phrases) and len(message.split()) < 6
219
-
220
- if is_ambiguous and last_mode:
221
- # For short, ambiguous messages, stick with the last mode
222
- if last_mode == 'math':
223
- return math_template, "Math Mode"
224
- elif last_mode == 'research':
225
- return research_template, "Research Mode"
226
- elif last_mode == 'study':
227
- return study_template, "Study Mode"
228
-
229
- # Determine the best mode based on scores
230
- max_score = max(final_scores.values())
231
-
232
- if max_score == 0:
233
- return general_template, "General Mode"
234
-
235
- # Return the mode with the highest score
236
- if final_scores['math'] == max_score:
237
- return math_template, "Math Mode"
238
- elif final_scores['research'] == max_score:
239
- return research_template, "Research Mode"
240
- elif final_scores['study'] == max_score:
241
- return study_template, "Study Mode"
242
- else:
243
- return general_template, "General Mode"
244
 
245
  def smart_truncate(text, max_length=3000):
246
  """Truncates text intelligently to the last full sentence or word."""
@@ -257,52 +148,26 @@ def smart_truncate(text, max_length=3000):
257
  return ' '.join(words[:-1]) + "... [Response truncated - ask for continuation]"
258
 
259
  def respond_with_enhanced_streaming(message, history):
260
- """Streams the bot's response, detecting the subject and handling errors."""
261
 
262
  # Start metrics timing
263
  timing_context = metrics_tracker.start_timing()
264
  error_occurred = False
265
  error_message = None
266
  response = ""
267
- mode = ""
268
 
269
  try:
270
- # UPDATED: Pass history to detect_subject
271
- template, mode = detect_subject(message, history)
272
-
273
- # Build conversation history with proper LangChain message objects
274
- messages = []
275
-
276
- # Add system message
277
- system_msg = SystemMessage(content=ENHANCED_SYSTEM_MESSAGE)
278
- messages.append(system_msg)
279
-
280
- # Add conversation history if available
281
  if history:
282
- for exchange in history[-5:]: # Keep last 5 exchanges for context
283
  if exchange.get("role") == "user":
284
- messages.append(HumanMessage(content=exchange["content"]))
285
  elif exchange.get("role") == "assistant":
286
- messages.append(AIMessage(content=exchange["content"]))
287
 
288
  # Add current user message
289
- messages.append(HumanMessage(content=message))
290
-
291
- yield f"*{mode}*\n\nGenerating response..."
292
-
293
- logger.info(f"Processing {mode} query: {message[:50]}...")
294
-
295
- # Use LangChain template to format the prompt
296
- formatted_prompt = template.format(
297
- question=message,
298
- system_message=ENHANCED_SYSTEM_MESSAGE
299
- )
300
-
301
- # Use chat completions instead of text_generation (more reliable)
302
- api_messages = [
303
- {"role": "system", "content": "You are EduBot, an expert AI learning assistant."},
304
- {"role": "user", "content": formatted_prompt}
305
- ]
306
 
307
  # Mark provider API start
308
  metrics_tracker.mark_provider_start(timing_context)
@@ -318,46 +183,41 @@ def respond_with_enhanced_streaming(message, history):
318
  # Mark provider API end
319
  metrics_tracker.mark_provider_end(timing_context)
320
 
321
- response = completion.choices[0].message.content
322
- response = smart_truncate(response, max_length=3000)
323
 
324
- # Stream the response word by word
325
  words = response.split()
326
- partial_response = f"*{mode}*\n\n"
327
 
328
  for i, word in enumerate(words):
329
  partial_response += word + " "
330
-
331
- # Update the stream periodically and record chunks
332
  if i % 4 == 0:
333
  metrics_tracker.record_chunk(timing_context)
334
  yield partial_response
335
  time.sleep(0.03)
336
 
337
- final_response = f"*{mode}*\n\n{response}"
338
  logger.info(f"Response completed. Length: {len(response)} characters")
339
 
340
- # Record final chunk
341
  metrics_tracker.record_chunk(timing_context)
342
- yield final_response
343
-
344
  except Exception as e:
345
  error_occurred = True
346
  error_message = str(e)
347
  logger.exception("Error in response generation")
348
- yield f"Sorry, I encountered an error: {str(e)}"
349
 
350
  finally:
351
- # Log the complete interaction with metrics
352
  metrics_tracker.log_interaction(
353
- mode=mode or "Unknown",
354
  query=message,
355
  response=response,
356
  timing_context=timing_context,
357
  error_occurred=error_occurred,
358
- error_message=error_message
359
  )
360
 
 
 
361
  # ===============================================================================
362
  # UI CONFIGURATION SECTION - ALL UI RELATED CODE CENTRALIZED HERE
363
  # ===============================================================================
 
76
  - Encourage students to explain their thinking and reasoning
77
  - Provide honest, accurate feedback even when it may not be what the student wants to hear
78
 
79
+ ## Modes
80
+ **Select the mode that best matches the user's needs.**
81
 
82
+ **Math Mode**
 
 
83
  LaTeX formatting is enabled for math. You must provide LaTeX formatting for all math, either as inline LaTeX or centered display LaTeX.
84
  You will address requests to solve, aid in understanding, or explore mathematical context. Use logical ordering for content, providing necessary terms and definitions as well as concept explanations along with math to foster understanding of core concepts. Rather than specifically answering the math problem provided, begin with solving a similar problem that requires the same steps and foundational mathematical knowledge, then prompt the user to work through the problem themselves. If the user insists you solve the problem, engage in a two-way conversation where you provide the steps but request the user solve for the answer one step at a time.
85
  LaTeX should always be used for math.
86
  LaTeX Examples:
87
  - Inline: "The slope is $m = \\frac{{y_2 - y_1}}{{x_2 - x_1}}$ in this case."
88
  - Display: "The quadratic formula is: $x = \\frac{{-b \\pm \\sqrt{{b^2-4ac}}}}{{2a}}$"
89
+ Always use double backslashes (\\\\) for LaTeX commands like \\\\frac, \\\\sqrt, \\\\int, etc.
 
 
90
 
91
+ **Research Mode**
 
 
92
  Your main goal is to help the user learn to research topics, a critical skill. Function as a partner rather than a search engine.
93
  Over the course of the conversation, guide the user through a seven-step research process:
94
  1) **Identifying a topic**
 
115
  IEEE Style
116
  In-text: [1]
117
  Reference: [1] J. A. Smith, Book Title. Publisher, 2023.
118
+ In this mode you may not use LaTeX formatting.
 
 
119
 
120
+ **Study Mode**
 
 
121
  Engage the user in a mix of two teaching styles: student-centered and inquiry-based learning.
122
  Student Centered: Adjust to reflect the student's reading level and level of understanding of a topic as the conversation progresses. Do not assume the user is an expert but instead assume they may have familiarity but desire to learn more about the topic they are studying. Provide definitions for terms you use in a conversational way, gradually shifting to using just the terms without definitions as the user becomes more familiar with them.
123
  Inquiry-based learning: Engage the user through questions that compel them to consider what they want to know and then explore the topics through guided conversation.
124
  Over the course of the conversation, prompt the user with a question to gauge their growing knowledge or progress on the topic.
125
  For example:
126
  After two to three turns of conversation discussing a topic, pick a specific term or concept from the conversation history to craft either a multiple-choice or written answer question for the user with no other comments along with it. If the student is correct, congratulate them on their progress and inquire about their next learning goal on the topic. If the user fails the question, return with a short response that explains the correct answer in a kind tone.
127
+ In this mode you may not use LaTeX formatting.
128
+
129
+ **General/Other Mode**
130
+ You are EduBot, a comprehensive AI learning assistant. Help users leverage educational tools and resources to enrich their education. Offer yourself as a resource for the student, prompting them to request help with **math topics**, **research strategy**, or **studying a topic**.
131
 
132
+ Your goal is to be an educational partner who empowers students to succeed through understanding, not a service that completes their work for them."""
 
 
 
 
 
133
 
134
  # --- Core Logic Functions ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
 
136
  def smart_truncate(text, max_length=3000):
137
  """Truncates text intelligently to the last full sentence or word."""
 
148
  return ' '.join(words[:-1]) + "... [Response truncated - ask for continuation]"
149
 
150
  def respond_with_enhanced_streaming(message, history):
151
+ """Streams the bot's response, handling errors with metrics tracking."""
152
 
153
  # Start metrics timing
154
  timing_context = metrics_tracker.start_timing()
155
  error_occurred = False
156
  error_message = None
157
  response = ""
 
158
 
159
  try:
160
+ # Build conversation history (last 5 exchanges)
161
+ api_messages = [{"role": "system", "content": ENHANCED_SYSTEM_MESSAGE}]
 
 
 
 
 
 
 
 
 
162
  if history:
163
+ for exchange in history[-5:]:
164
  if exchange.get("role") == "user":
165
+ api_messages.append({"role": "user", "content": exchange["content"]})
166
  elif exchange.get("role") == "assistant":
167
+ api_messages.append({"role": "assistant", "content": exchange["content"]})
168
 
169
  # Add current user message
170
+ api_messages.append({"role": "user", "content": message})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
  # Mark provider API start
173
  metrics_tracker.mark_provider_start(timing_context)
 
183
  # Mark provider API end
184
  metrics_tracker.mark_provider_end(timing_context)
185
 
186
+ response = smart_truncate(completion.choices[0].message.content, max_length=3000)
 
187
 
188
+ # Stream fake-chunks word by word
189
  words = response.split()
190
+ partial_response = ""
191
 
192
  for i, word in enumerate(words):
193
  partial_response += word + " "
 
 
194
  if i % 4 == 0:
195
  metrics_tracker.record_chunk(timing_context)
196
  yield partial_response
197
  time.sleep(0.03)
198
 
 
199
  logger.info(f"Response completed. Length: {len(response)} characters")
200
 
 
201
  metrics_tracker.record_chunk(timing_context)
202
+ yield response
203
+
204
  except Exception as e:
205
  error_occurred = True
206
  error_message = str(e)
207
  logger.exception("Error in response generation")
208
+ yield "Sorry, I encountered an error while generating the response."
209
 
210
  finally:
 
211
  metrics_tracker.log_interaction(
 
212
  query=message,
213
  response=response,
214
  timing_context=timing_context,
215
  error_occurred=error_occurred,
216
+ error_message=error_message,
217
  )
218
 
219
+
220
+
221
  # ===============================================================================
222
  # UI CONFIGURATION SECTION - ALL UI RELATED CODE CENTRALIZED HERE
223
  # ===============================================================================