jdesiree commited on
Commit
3dd3d1c
ยท
verified ยท
1 Parent(s): dce2284

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -132
app.py CHANGED
@@ -5,19 +5,28 @@ from langchain.schema import HumanMessage, SystemMessage
5
  from langchain.callbacks.base import BaseCallbackHandler
6
  import os
7
  import time
 
 
8
 
9
- # Custom streaming callback for Gradio
 
 
 
 
10
  class GradioStreamingCallback(BaseCallbackHandler):
11
- """Custom LangChain callback for streaming to Gradio"""
12
 
13
  def __init__(self):
14
  self.text = ""
15
  self.tokens = []
 
16
 
17
  def on_llm_start(self, serialized, prompts, **kwargs):
18
  """Called when LLM starts generating"""
19
  self.text = ""
20
  self.tokens = []
 
 
21
 
22
  def on_llm_new_token(self, token: str, **kwargs):
23
  """Called when LLM generates a new token"""
@@ -27,70 +36,81 @@ class GradioStreamingCallback(BaseCallbackHandler):
27
 
28
  def on_llm_end(self, response, **kwargs):
29
  """Called when LLM finishes generating"""
30
- pass
 
31
 
32
  def on_llm_error(self, error, **kwargs):
33
  """Called when LLM encounters an error"""
 
 
34
  self.text += f"\n[Error: {str(error)[:100]}]"
35
 
36
- # Set up LangChain model with streaming capabilities
37
  llm = HuggingFaceEndpoint(
38
  repo_id="HuggingFaceH4/zephyr-7b-beta",
39
  temperature=0.7,
40
  top_p=0.9,
41
  repetition_penalty=1.1,
42
- model_kwargs={"max_length": 1536},
43
  huggingfacehub_api_token=os.getenv("HUGGINGFACEHUB_API_TOKEN")
44
  )
45
 
46
- # Enhanced prompt templates with streaming instructions
47
  math_template = ChatPromptTemplate.from_messages([
48
- ("system", """You are an expert math tutor. For every math problem:
49
- 1. Break it down step-by-step with detailed explanations
50
- 2. Explain the reasoning behind each step thoroughly
51
- 3. Show all work clearly with proper mathematical notation
52
- 4. Check your answer and explain why it's correct
53
- 5. Provide additional examples if helpful
54
- 6. Explain the underlying mathematical concepts
55
-
56
- Be comprehensive and educational. Structure your response clearly with proper spacing."""),
 
 
57
  ("human", "{question}")
58
  ])
59
 
60
  research_template = ChatPromptTemplate.from_messages([
61
- ("system", """You are a research skills mentor. Help students with:
62
- - Finding reliable and credible sources
63
- - Evaluating source credibility and bias
64
- - Proper citation formats (APA, MLA, Chicago, etc.)
65
- - Research strategies and methodologies
66
- - Academic writing techniques and structure
67
- - Database navigation and search strategies
68
-
69
- Provide detailed, actionable advice with specific examples and clear formatting."""),
 
 
70
  ("human", "{question}")
71
  ])
72
 
73
  study_template = ChatPromptTemplate.from_messages([
74
- ("system", """You are a study skills coach. Help students with:
75
- - Effective study methods for different learning styles
76
- - Time management and scheduling techniques
77
- - Memory techniques and retention strategies
78
- - Test preparation and exam strategies
79
- - Note-taking methods and organization
80
- - Learning style optimization
81
-
82
- Provide comprehensive, personalized advice with practical examples and clear structure."""),
 
 
83
  ("human", "{question}")
84
  ])
85
 
86
  general_template = ChatPromptTemplate.from_messages([
87
- ("system", """You are EduBot, a comprehensive AI learning assistant. You help students with:
88
- ๐Ÿ“ Mathematics (detailed step-by-step solutions and concept explanations)
89
- ๐Ÿ” Research skills (source finding, evaluation, and citation)
90
- ๐Ÿ“š Study strategies (effective learning techniques and exam preparation)
91
- ๐Ÿ› ๏ธ Educational tools (guidance on learning resources and technologies)
92
-
93
- Always be encouraging, patient, thorough, and comprehensive. Structure responses clearly."""),
 
 
94
  ("human", "{question}")
95
  ])
96
 
@@ -111,68 +131,22 @@ def detect_subject(message):
111
  else:
112
  return general_template, "๐ŸŽ“ General Mode"
113
 
114
- def respond_with_langchain_streaming(
115
- message,
116
- history: list[tuple[str, str]],
117
- system_message,
118
- max_tokens,
119
- temperature,
120
- top_p,
121
- ):
122
- """Custom LangChain streaming implementation for Gradio"""
123
 
124
- try:
125
- # Select appropriate template and mode
126
- template, mode = detect_subject(message)
127
-
128
- # Create custom streaming callback
129
- streaming_callback = GradioStreamingCallback()
130
-
131
- # Create the LangChain chain
132
- chain = template | llm
133
-
134
- # Configure streaming with callbacks
135
- config = {
136
- "callbacks": [streaming_callback],
137
- "metadata": {"mode": mode}
138
- }
139
-
140
- # Start streaming response
141
- partial_response = f"*{mode}*\n\n"
142
- yield partial_response
143
-
144
- # Invoke LangChain with streaming
145
- try:
146
- # Get the response (this triggers the callbacks)
147
- response = chain.invoke(
148
- {"question": message},
149
- config=config
150
- )
151
-
152
- # Handle the streaming output
153
- if hasattr(streaming_callback, 'text') and streaming_callback.text:
154
- # Use the streamed text from callback
155
- final_text = streaming_callback.text
156
- else:
157
- # Fallback to direct response
158
- final_text = str(response)
159
-
160
- # Clean up the response
161
- if len(final_text) > 4000:
162
- final_text = final_text[:4000] + "... [Response truncated - ask for continuation]"
163
-
164
- # Yield the complete response
165
- full_response = f"*{mode}*\n\n{final_text}"
166
- yield full_response
167
-
168
- except Exception as invoke_error:
169
- yield f"*{mode}*\n\nSorry, I encountered an error while generating the response: {str(invoke_error)[:200]}"
170
-
171
- except Exception as e:
172
- yield f"Sorry, I encountered an error: {str(e)[:200]}"
173
 
174
- # Alternative: Simulated Streaming (More Reliable)
175
- def respond_with_simulated_streaming(
176
  message,
177
  history: list[tuple[str, str]],
178
  system_message,
@@ -180,7 +154,7 @@ def respond_with_simulated_streaming(
180
  temperature,
181
  top_p,
182
  ):
183
- """Simulated streaming that chunks a complete LangChain response"""
184
 
185
  try:
186
  # Select template and get mode
@@ -192,66 +166,135 @@ def respond_with_simulated_streaming(
192
  # Show initial mode
193
  yield f"*{mode}*\n\nGenerating response..."
194
 
195
- # Get complete response from LangChain (no streaming)
196
- response = chain.invoke({"question": message})
197
 
198
- # Clean the response
199
- if len(response) > 4000:
200
- response = response[:4000] + "... [Response truncated - ask for continuation]"
 
 
 
 
201
 
202
  # Simulate streaming by chunking the response
203
  words = response.split()
204
  partial_response = f"*{mode}*\n\n"
205
 
206
- # Stream word by word
207
  for i, word in enumerate(words):
208
  partial_response += word + " "
209
 
210
- # Update every few words for smooth streaming effect
211
- if i % 3 == 0: # Update every 3 words
212
  yield partial_response
213
- time.sleep(0.05) # Small delay for streaming effect
214
 
215
  # Final complete response
216
- yield f"*{mode}*\n\n{response}"
 
 
217
 
218
  except Exception as e:
219
- yield f"Sorry, I encountered an error: {str(e)[:200]}"
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
- # Create Gradio interface with custom streaming
222
  demo = gr.ChatInterface(
223
- respond_with_simulated_streaming, # Use simulated streaming (more reliable)
224
- # respond_with_langchain_streaming, # Use this for true LangChain streaming
225
- title="๐ŸŽ“ EduBot",
226
- description="Your comprehensive AI tutor",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  examples=[
228
- ["Solve the quadratic equation xยฒ + 5x + 6 = 0 with complete explanations"],
229
- ["How do I conduct a literature review for my psychology research paper?"],
230
- ["Create a comprehensive study schedule for my final exams"],
231
- ["Explain the concept of derivatives in calculus with real-world examples"],
232
- ["How do I properly format citations in APA style with examples?"]
233
  ],
234
  additional_inputs=[
235
  gr.Textbox(
236
- value="You are EduBot, powered by advanced LangChain streaming capabilities.",
237
- label="System message",
238
- visible=False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  ),
240
- gr.Slider(minimum=1, maximum=1536, value=800, step=1, label="Max new tokens"),
241
- gr.Slider(minimum=0.1, maximum=2.0, value=0.7, step=0.1, label="Temperature"),
242
  gr.Slider(
243
  minimum=0.1,
244
  maximum=1.0,
245
  value=0.9,
246
  step=0.05,
247
- label="Top-p (nucleus sampling)",
 
248
  ),
249
  ],
250
- theme=gr.themes.Soft(
251
- primary_hue="blue",
252
- secondary_hue="green"
 
 
 
 
 
 
 
 
 
 
253
  ),
 
 
 
254
  )
255
 
256
  if __name__ == "__main__":
257
- demo.launch()
 
 
 
 
 
 
 
5
  from langchain.callbacks.base import BaseCallbackHandler
6
  import os
7
  import time
8
+ import logging
9
+ import re
10
 
11
+ # Set up logging for better debugging
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger = logging.getLogger(__name__)
14
+
15
+ # Custom streaming callback with improved behavior
16
  class GradioStreamingCallback(BaseCallbackHandler):
17
+ """Enhanced LangChain callback for streaming to Gradio"""
18
 
19
  def __init__(self):
20
  self.text = ""
21
  self.tokens = []
22
+ self.is_streaming = False
23
 
24
  def on_llm_start(self, serialized, prompts, **kwargs):
25
  """Called when LLM starts generating"""
26
  self.text = ""
27
  self.tokens = []
28
+ self.is_streaming = True
29
+ logger.info("LLM generation started")
30
 
31
  def on_llm_new_token(self, token: str, **kwargs):
32
  """Called when LLM generates a new token"""
 
36
 
37
  def on_llm_end(self, response, **kwargs):
38
  """Called when LLM finishes generating"""
39
+ self.is_streaming = False
40
+ logger.info(f"LLM generation completed. Total tokens: {len(self.tokens)}")
41
 
42
  def on_llm_error(self, error, **kwargs):
43
  """Called when LLM encounters an error"""
44
+ self.is_streaming = False
45
+ logger.error(f"LLM error: {error}")
46
  self.text += f"\n[Error: {str(error)[:100]}]"
47
 
48
+ # Set up LangChain model with conservative settings
49
  llm = HuggingFaceEndpoint(
50
  repo_id="HuggingFaceH4/zephyr-7b-beta",
51
  temperature=0.7,
52
  top_p=0.9,
53
  repetition_penalty=1.1,
54
+ model_kwargs={"max_length": 1024}, # More conservative
55
  huggingfacehub_api_token=os.getenv("HUGGINGFACEHUB_API_TOKEN")
56
  )
57
 
58
+ # Enhanced prompt templates that use system_message parameter
59
  math_template = ChatPromptTemplate.from_messages([
60
+ ("system", """{system_message}
61
+
62
+ You are an expert math tutor. For every math problem:
63
+ 1. Break it down step-by-step with detailed explanations
64
+ 2. Explain the reasoning behind each step thoroughly
65
+ 3. Show all work clearly with proper mathematical notation
66
+ 4. Check your answer and explain why it's correct
67
+ 5. Provide additional examples if helpful
68
+ 6. Explain the underlying mathematical concepts
69
+
70
+ Be comprehensive and educational. Structure your response clearly."""),
71
  ("human", "{question}")
72
  ])
73
 
74
  research_template = ChatPromptTemplate.from_messages([
75
+ ("system", """{system_message}
76
+
77
+ You are a research skills mentor. Help students with:
78
+ - Finding reliable and credible sources
79
+ - Evaluating source credibility and bias
80
+ - Proper citation formats (APA, MLA, Chicago, etc.)
81
+ - Research strategies and methodologies
82
+ - Academic writing techniques and structure
83
+ - Database navigation and search strategies
84
+
85
+ Provide detailed, actionable advice with specific examples."""),
86
  ("human", "{question}")
87
  ])
88
 
89
  study_template = ChatPromptTemplate.from_messages([
90
+ ("system", """{system_message}
91
+
92
+ You are a study skills coach. Help students with:
93
+ - Effective study methods for different learning styles
94
+ - Time management and scheduling techniques
95
+ - Memory techniques and retention strategies
96
+ - Test preparation and exam strategies
97
+ - Note-taking methods and organization
98
+ - Learning style optimization
99
+
100
+ Provide comprehensive, personalized advice with practical examples."""),
101
  ("human", "{question}")
102
  ])
103
 
104
  general_template = ChatPromptTemplate.from_messages([
105
+ ("system", """{system_message}
106
+
107
+ You are EduBot, a comprehensive AI learning assistant. You help students with:
108
+ ๐Ÿ“ Mathematics (detailed step-by-step solutions and concept explanations)
109
+ ๐Ÿ” Research skills (source finding, evaluation, and citation)
110
+ ๐Ÿ“š Study strategies (effective learning techniques and exam preparation)
111
+ ๐Ÿ› ๏ธ Educational tools (guidance on learning resources and technologies)
112
+
113
+ Always be encouraging, patient, thorough, and comprehensive."""),
114
  ("human", "{question}")
115
  ])
116
 
 
131
  else:
132
  return general_template, "๐ŸŽ“ General Mode"
133
 
134
+ def smart_truncate(text, max_length=3000):
135
+ """Intelligently truncate text at sentence boundaries"""
136
+ if len(text) <= max_length:
137
+ return text
 
 
 
 
 
138
 
139
+ # Try to cut at last complete sentence
140
+ sentences = re.split(r'(?<=[.!?]) +', text[:max_length])
141
+ if len(sentences) > 1:
142
+ # Remove the last incomplete sentence
143
+ return ' '.join(sentences[:-1]) + "... [Response truncated - ask for continuation]"
144
+ else:
145
+ # Fallback to word boundary
146
+ words = text[:max_length].split()
147
+ return ' '.join(words[:-1]) + "... [Response truncated - ask for continuation]"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ def respond_with_enhanced_streaming(
 
150
  message,
151
  history: list[tuple[str, str]],
152
  system_message,
 
154
  temperature,
155
  top_p,
156
  ):
157
+ """Enhanced LangChain implementation with proper system message handling"""
158
 
159
  try:
160
  # Select template and get mode
 
166
  # Show initial mode
167
  yield f"*{mode}*\n\nGenerating response..."
168
 
169
+ # Get complete response from LangChain with system message
170
+ logger.info(f"Processing {mode} query: {message[:50]}...")
171
 
172
+ response = chain.invoke({
173
+ "question": message,
174
+ "system_message": system_message or "You are EduBot, an AI learning assistant."
175
+ })
176
+
177
+ # Smart truncation at sentence boundaries
178
+ response = smart_truncate(response, max_length=3000)
179
 
180
  # Simulate streaming by chunking the response
181
  words = response.split()
182
  partial_response = f"*{mode}*\n\n"
183
 
184
+ # Stream word by word for better UX
185
  for i, word in enumerate(words):
186
  partial_response += word + " "
187
 
188
+ # Update every 4 words for smooth streaming effect
189
+ if i % 4 == 0:
190
  yield partial_response
191
+ time.sleep(0.03) # Slightly faster streaming
192
 
193
  # Final complete response
194
+ final_response = f"*{mode}*\n\n{response}"
195
+ logger.info(f"Response completed. Length: {len(response)} characters")
196
+ yield final_response
197
 
198
  except Exception as e:
199
+ logger.exception("Error in LangChain response generation")
200
+ yield f"Sorry, I encountered an error: {str(e)[:150]}"
201
+
202
+ # Create enhanced Gradio interface with custom theme
203
+ custom_theme = gr.themes.Soft(
204
+ primary_hue="blue",
205
+ secondary_hue="green",
206
+ neutral_hue="slate",
207
+ ).set(
208
+ body_background_fill="linear-gradient(45deg, #f0f9ff, #ecfdf5)",
209
+ button_primary_background_fill="#2563eb",
210
+ button_primary_text_color="white",
211
+ )
212
 
213
+ # Create the main interface
214
  demo = gr.ChatInterface(
215
+ respond_with_enhanced_streaming,
216
+ title="๐ŸŽ“ EduBot | AI Learning Assistant",
217
+ description="""
218
+ **Your comprehensive AI tutor powered by LangChain!**
219
+
220
+ ๐Ÿ”ง **Technical Features:**
221
+ โ€ข Dynamic prompt templates based on question type
222
+ โ€ข LangChain chain composition with `|` operator
223
+ โ€ข Smart response truncation at sentence boundaries
224
+ โ€ข Enhanced error handling and logging
225
+
226
+ ๐Ÿ“š **Educational Modes:**
227
+ โ€ข ๐Ÿงฎ **Math Mode** - Step-by-step problem solving with detailed explanations
228
+ โ€ข ๐Ÿ” **Research Mode** - Source finding, evaluation, and citation guidance
229
+ โ€ข ๐Ÿ“š **Study Mode** - Learning strategies and exam preparation techniques
230
+ โ€ข ๐ŸŽ“ **General Mode** - Comprehensive educational support
231
+
232
+ ๐Ÿ’ก **Tip:** Try asking detailed questions for thorough explanations!
233
+ """,
234
  examples=[
235
+ ["Solve the quadratic equation xยฒ + 5x + 6 = 0 with complete step-by-step explanations"],
236
+ ["How do I conduct a comprehensive literature review for my psychology research paper?"],
237
+ ["Create a detailed study schedule for my calculus and chemistry final exams"],
238
+ ["Explain derivatives in calculus with real-world applications and examples"],
239
+ ["How do I properly format citations in APA style with detailed guidelines?"]
240
  ],
241
  additional_inputs=[
242
  gr.Textbox(
243
+ value="You are EduBot, an expert AI learning assistant. Provide comprehensive, educational responses that help students truly understand concepts.",
244
+ label="Custom System Message",
245
+ placeholder="Customize how EduBot behaves...",
246
+ lines=2,
247
+ visible=True # Make it visible so users can customize
248
+ ),
249
+ gr.Slider(
250
+ minimum=1,
251
+ maximum=1024,
252
+ value=600,
253
+ step=1,
254
+ label="Max Tokens",
255
+ info="Higher values = longer responses"
256
+ ),
257
+ gr.Slider(
258
+ minimum=0.1,
259
+ maximum=2.0,
260
+ value=0.7,
261
+ step=0.1,
262
+ label="Temperature",
263
+ info="Higher values = more creative responses"
264
  ),
 
 
265
  gr.Slider(
266
  minimum=0.1,
267
  maximum=1.0,
268
  value=0.9,
269
  step=0.05,
270
+ label="Top-p",
271
+ info="Controls response diversity"
272
  ),
273
  ],
274
+ theme=custom_theme,
275
+ chatbot=gr.Chatbot(
276
+ height=500,
277
+ show_copy_button=True,
278
+ avatar_images=["๐Ÿ‘ค", "๐ŸŽ“"],
279
+ bubble_full_width=False,
280
+ show_share_button=True,
281
+ placeholder="Hi! I'm EduBot. What would you like to learn today? ๐Ÿ“š"
282
+ ),
283
+ textbox=gr.Textbox(
284
+ placeholder="Ask me about math, research, study strategies, or any educational topic...",
285
+ container=False,
286
+ scale=7
287
  ),
288
+ retry_btn="๐Ÿ”„ Retry",
289
+ undo_btn="โ†ฉ๏ธ Undo",
290
+ clear_btn="๐Ÿ—‘๏ธ Clear",
291
  )
292
 
293
  if __name__ == "__main__":
294
+ logger.info("Starting EduBot application...")
295
+ demo.launch(
296
+ share=False, # Set to True if you want a public link
297
+ show_error=True,
298
+ favicon_path=None,
299
+ show_api=False
300
+ )