ciaochris commited on
Commit
bd3ead1
·
verified ·
1 Parent(s): bdf1a51

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -213
app.py CHANGED
@@ -10,9 +10,9 @@ from typing import Dict, Any, Tuple
10
  from dotenv import load_dotenv
11
  import markdown2
12
 
13
- # Set up more detailed logging
14
  logging.basicConfig(
15
- level=logging.DEBUG, # Changed to DEBUG for more verbose output
16
  format='%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s',
17
  handlers=[
18
  logging.StreamHandler(sys.stdout),
@@ -27,7 +27,7 @@ logging.debug("Environment variables loaded")
27
  # Print environment check
28
  logging.debug(f"GROQ_API_KEY present: {bool(os.getenv('GROQ_API_KEY'))}")
29
 
30
- # Initialize Groq client with extensive error handling
31
  try:
32
  api_key = os.getenv("GROQ_API_KEY")
33
  if not api_key:
@@ -57,20 +57,16 @@ def transcribe_audio(audio):
57
 
58
  logging.debug(f"Audio input received: {type(audio)} - {audio}")
59
 
60
- # Check if audio is a path string or a file object
61
  audio_path = audio if isinstance(audio, str) else audio
62
-
63
  logging.debug(f"Audio path: {audio_path}")
64
  logging.debug(f"File exists: {os.path.exists(audio_path) if audio_path else False}")
65
 
66
- # Handle audio file properly based on gradio's audio component output
67
  if audio_path and os.path.exists(audio_path):
68
  with open(audio_path, "rb") as audio_file:
69
  audio_data = audio_file.read()
70
 
71
  logging.debug(f"Audio file opened, size: {len(audio_data)} bytes")
72
 
73
- # Use the correct API endpoint and parameters for Groq's audio transcription
74
  try:
75
  logging.debug("Sending audio to Groq API for transcription")
76
  transcription = client.audio.transcriptions.create(
@@ -80,26 +76,22 @@ def transcribe_audio(audio):
80
 
81
  logging.debug(f"Transcription response received: {transcription}")
82
 
83
- # Check the structure of the response
84
  if hasattr(transcription, 'text'):
85
  result = transcription.text
86
  logging.debug(f"Transcription text: {result}")
87
  return result
88
  else:
89
- # Handle different response structure
90
  result = transcription.get('text', "Transcription succeeded but returned no text")
91
  logging.debug(f"Transcription text (alt format): {result}")
92
  return result
93
  except Exception as e:
94
  logging.error(f"Audio transcription API error: {str(e)}")
95
- logging.error(traceback.format_exc())
96
  return f"Audio transcription failed: {str(e)}"
97
  else:
98
  logging.warning(f"Audio file not found at path: {audio_path}")
99
  return "Audio file not found. Please try recording again."
100
  except Exception as e:
101
  logging.error(f"Error in transcription: {str(e)}")
102
- logging.error(traceback.format_exc())
103
  return f"Error in transcription: {str(e)}"
104
 
105
  def generate_tutor_output(subject: str, difficulty: str, student_input: str) -> Dict[str, str]:
@@ -124,13 +116,9 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
124
  "dna replication": "the process of DNA replication and its importance in cell division",
125
  "climate change": "the causes and effects of climate change, including global warming and its impact on ecosystems"
126
  },
127
- # Add more subjects and topics as needed
128
  }
129
 
130
- # Normalize subject to lowercase for matching
131
  subject_lower = subject.lower() if subject else "general"
132
-
133
- # Check if it's a specific topic and create an enhanced prompt
134
  enhanced_topic = None
135
  for subj, subject_topics in topics.items():
136
  for topic, description in subject_topics.items():
@@ -141,7 +129,6 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
141
  if enhanced_topic:
142
  break
143
 
144
- # Create the prompt based on whether it's a specific topic or not
145
  if enhanced_topic:
146
  logging.debug(f"Using enhanced topic: {enhanced_topic}")
147
  prompt = f"""
@@ -173,120 +160,84 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
173
  Ensure that the content for each key is a single string, with line breaks where appropriate.
174
  """
175
 
176
- # Validate API models
177
- try:
178
- models = client.models.list()
179
- model_ids = [m.id for m in models.data]
180
- logging.debug(f"Available models: {model_ids}")
181
-
182
- # Check if our target model is available
183
- target_model = "llama-3.3-70b-versatile"
184
- if target_model not in model_ids:
185
- logging.warning(f"Model {target_model} not found. Using fallback model.")
186
- # Use a fallback model if the target model is not available
187
- target_model = model_ids[0] if model_ids else "llama-3.3-70b-versatile"
188
- logging.debug(f"Using fallback model: {target_model}")
189
- except Exception as e:
190
- logging.error(f"Error checking models: {e}")
191
- target_model = "llama-3.3-70b-versatile"
192
-
193
  logging.debug(f"Sending prompt to model: {target_model}")
194
 
195
- # Make API call to Groq
196
- try:
197
- completion = client.chat.completions.create(
198
- messages=[
199
- {
200
- "role": "system",
201
- "content": f"You are the world's best AI tutor, renowned for your ability to explain complex concepts in an engaging, clear, and memorable way. Your expertise in {subject_lower} is unparalleled, and you're adept at tailoring your teaching to {difficulty} level students. Your goal is to not just impart knowledge, but to inspire a love for learning and critical thinking.",
202
- },
203
- {
204
- "role": "user",
205
- "content": prompt,
206
- }
207
- ],
208
- model=target_model,
209
- max_tokens=2000,
210
- )
211
-
212
- # Handle the response parsing more robustly
213
- response_content = completion.choices[0].message.content
214
- logging.debug(f"Received response: {response_content[:100]}...") # Log first 100 chars
215
-
216
- # Try to parse the JSON directly
217
- try:
218
- result = json.loads(response_content)
219
- logging.debug("Successfully parsed JSON response")
220
- return result
221
- except json.JSONDecodeError as e:
222
- logging.warning(f"Failed to parse JSON response: {e}")
223
-
224
- # Try to extract JSON-like structure
225
- json_match = re.search(r'\{[\s\S]*\}', response_content)
226
- if json_match:
227
- try:
228
- result = json.loads(json_match.group(0))
229
- logging.debug("Successfully extracted and parsed JSON from response")
230
- return result
231
- except json.JSONDecodeError as e2:
232
- logging.warning(f"Failed to parse extracted JSON: {e2}")
233
-
234
- # If JSON parsing fails, create a structured response
235
- logging.debug("Creating structured response from plain text")
236
- sections = {
237
- "lesson": "",
238
- "example": "",
239
- "real_world_problem": "",
240
- "quiz": ""
241
  }
242
-
243
- # Try to extract sections based on headers
244
- current_section = None
245
- lines = response_content.split('\n')
246
- for line in lines:
247
- line = line.strip()
248
- if "Lesson:" in line or line.startswith("1."):
249
- current_section = "lesson"
250
- sections[current_section] += line.replace("Lesson:", "").replace("1.", "").strip() + "\n"
251
- elif "Example:" in line or line.startswith("2."):
252
- current_section = "example"
253
- sections[current_section] += line.replace("Example:", "").replace("2.", "").strip() + "\n"
254
- elif "Real-World Application:" in line or "Real-World Problem:" in line or line.startswith("3."):
255
- current_section = "real_world_problem"
256
- sections[current_section] += line.replace("Real-World Application:", "").replace("Real-World Problem:", "").replace("3.", "").strip() + "\n"
257
- elif "Quiz:" in line or line.startswith("4."):
258
- current_section = "quiz"
259
- sections[current_section] += line.replace("Quiz:", "").replace("4.", "").strip() + "\n"
260
- elif current_section:
261
- sections[current_section] += line + "\n"
262
-
263
- return sections
264
-
265
- except Exception as e:
266
- logging.error(f"Error calling Groq API: {str(e)}")
267
- logging.error(traceback.format_exc())
268
- return {"error": f"Failed to generate tutor output: {str(e)}"}
269
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  except Exception as e:
271
  logging.error(f"Error in generate_tutor_output: {str(e)}")
272
  logging.error(traceback.format_exc())
273
- return {"error": f"Failed to generate tutor output: {str(e)}"}
 
 
 
 
 
274
 
275
  def process_output(output: Dict[str, Any]) -> Tuple[str, str, str, str]:
276
  """Process the output from generate_tutor_output into HTML format."""
277
  try:
278
  logging.debug(f"Processing output: {str(output)[:100]}...")
279
 
280
- if "error" in output:
281
- error_msg = output.get("error", "Unknown error occurred")
282
- logging.error(f"Error message in output: {error_msg}")
283
- return error_msg, "", "", ""
284
-
285
- # Use markdown2 to convert markdown to HTML, with fallbacks for missing content
286
- lesson = markdown2.markdown(str(output.get("lesson", "No lesson available")))
287
- example = markdown2.markdown(str(output.get("example", "No example available")))
288
- real_world = markdown2.markdown(str(output.get("real_world_problem", "No real-world problem available")))
289
- quiz = markdown2.markdown(str(output.get("quiz", "No quiz available")))
290
 
291
  logging.debug("Output processed successfully")
292
  return lesson, example, real_world, quiz
@@ -302,7 +253,6 @@ def create_interface() -> gr.Blocks:
302
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
303
  gr.Markdown("# 🎓 Vers3Dynamics Tutor: Your Personal Learning Companion")
304
 
305
- # Create a state variable to track submission
306
  state = gr.State({"is_submitting": False})
307
 
308
  with gr.Row():
@@ -311,32 +261,30 @@ def create_interface() -> gr.Blocks:
311
  ["Art History", "Computer Science", "Literature", "Math", "Music", "Science", "Social Science"],
312
  label="Subject",
313
  info="Choose the subject of your lesson",
314
- value="Math" # Set a default value
315
  )
316
  difficulty = gr.Radio(
317
  ["Primary", "Secondary", "Higher Education"],
318
  label="Difficulty Level",
319
  info="Select your proficiency level",
320
- value="Secondary" # Set a default value
321
  )
322
  student_input = gr.Textbox(
323
  placeholder="Type your topic or question here...",
324
  label="Type Your Question",
325
  info="Enter the topic you want to explore"
326
  )
327
- # Updated audio input configuration
328
  audio_input = gr.Audio(
329
- type="filepath",
330
  label="Speak Your Question",
331
  sources=["microphone"],
332
- format="wav" # Explicitly specify format
333
  )
334
 
335
  with gr.Row():
336
  submit_button = gr.Button("📚 Teach Me", variant="primary")
337
  clear_button = gr.Button("🧹 Clear", variant="secondary")
338
 
339
- # Add a status indicator
340
  status_indicator = gr.Textbox(
341
  label="Status",
342
  value="Ready",
@@ -374,131 +322,87 @@ def create_interface() -> gr.Blocks:
374
  def process_input(subject, difficulty, text_input, audio_input, state):
375
  """Process input from text or audio."""
376
  try:
377
- # Update state to indicate submission is in progress
378
- state = {"is_submitting": True}
379
-
380
- # Update status
381
- yield state, "Processing your request...", transcription_output.value, lesson_output.value, example_output.value, real_world_output.value, quiz_output.value
382
-
383
- # Add debug logging
384
  logging.info(f"Received inputs - subject: {subject}, difficulty: {difficulty}")
385
- logging.info(f"Text input: '{text_input}', Audio input type: {type(audio_input)}")
386
 
387
- # Check for subject
388
- if not subject:
389
- logging.warning("No subject provided, defaulting to Math")
390
- subject = "Math"
391
 
392
- # Check for difficulty
393
- if not difficulty:
394
- logging.warning("No difficulty provided, defaulting to Secondary")
395
- difficulty = "Secondary"
396
-
397
- # Check if any input is provided
398
- if (not text_input or text_input.strip() == "") and not audio_input:
399
- logging.warning("No input provided")
400
- yield (
401
  {"is_submitting": False},
402
  "Ready",
403
- "No input provided. Please type a question or record audio.",
404
- "Please provide a question to begin.",
405
  "",
406
  "",
407
  ""
408
  )
409
- return
410
-
411
- # Update status
412
- yield state, "Processing input...", transcription_output.value, lesson_output.value, example_output.value, real_world_output.value, quiz_output.value
413
 
414
- # Prioritize text input if available
415
- if text_input and text_input.strip():
416
  student_input = text_input.strip()
417
- transcribed_text = "Using text input instead of audio."
418
- logging.info(f"Using text input: {student_input}")
419
  elif audio_input:
420
- # Update status
421
- yield state, "Transcribing audio...", "Transcribing your audio...", lesson_output.value, example_output.value, real_world_output.value, quiz_output.value
422
-
423
  transcribed_text = transcribe_audio(audio_input)
424
  student_input = transcribed_text
425
- logging.info(f"Using transcribed audio: {student_input}")
426
-
427
- # Check if transcription was successful
428
- if not student_input or "error" in student_input.lower():
429
- yield (
430
  {"is_submitting": False},
431
  "Ready",
432
  transcribed_text,
433
- "Transcription error. Please try typing your question instead.",
434
  "",
435
  "",
436
  ""
437
  )
438
- return
439
  else:
440
- # This should not happen given the check above, but just to be safe
441
- logging.warning("No valid input detected")
442
- yield (
443
  {"is_submitting": False},
444
  "Ready",
445
- "No valid input detected. Please try again.",
446
- "Please provide a question.",
447
  "",
448
  "",
449
  ""
450
  )
451
- return
452
-
453
- # Update status
454
- yield state, "Generating educational content...", transcribed_text, "Generating lesson...", "Preparing examples...", "Finding applications...", "Creating quiz..."
455
 
456
- # Generate tutor output - use lowercase for subject
457
  tutor_output = generate_tutor_output(subject, difficulty, student_input)
458
- logging.info("Successfully generated tutor output")
459
-
460
- if "error" in tutor_output:
461
- error_msg = tutor_output.get("error", "Unknown error occurred")
462
- yield (
463
- {"is_submitting": False},
464
- "Ready",
465
- transcribed_text,
466
- f"Error: {error_msg}",
467
- "",
468
- "",
469
- ""
470
- )
471
- return
472
-
473
- # Update status
474
- yield state, "Formatting results...", transcribed_text, lesson_output.value, example_output.value, real_world_output.value, quiz_output.value
475
-
476
- # Process the output
477
  lesson, example, real_world, quiz = process_output(tutor_output)
478
- logging.info("Successfully processed output into formatted HTML")
479
-
480
- # Update state to indicate submission is complete
481
- yield {"is_submitting": False}, "Ready", transcribed_text, lesson, example, real_world, quiz
482
 
 
 
 
 
 
 
 
 
 
 
483
  except Exception as e:
484
  logging.error(f"Error in process_input: {str(e)}")
485
  logging.error(traceback.format_exc())
486
- error_message = f"Error processing your request: {str(e)}"
487
- yield {"is_submitting": False}, "Error", error_message, error_message, "", "", ""
 
 
 
 
 
 
 
488
 
489
  def clear_outputs():
490
  """Clear all inputs and outputs."""
491
  logging.debug("Clearing all outputs")
492
- return {"is_submitting": False}, "Ready", "", "", "", "", ""
493
 
494
- # Connect the submit button to process_input function
495
  submit_button.click(
496
  fn=process_input,
497
  inputs=[subject, difficulty, student_input, audio_input, state],
498
  outputs=[state, status_indicator, transcription_output, lesson_output, example_output, real_world_output, quiz_output]
499
  )
500
 
501
- # Connect the clear button to clear_outputs function
502
  clear_button.click(
503
  fn=clear_outputs,
504
  inputs=[],
@@ -507,22 +411,18 @@ def create_interface() -> gr.Blocks:
507
 
508
  return demo
509
 
510
- # Add a health check function and detailed error handling for startup
511
  def check_health():
512
  """Perform a health check of required components."""
513
  problems = []
514
 
515
- # Check environment variables
516
  if not os.getenv("GROQ_API_KEY"):
517
  problems.append("GROQ_API_KEY environment variable is not set")
518
 
519
- # Check if markdown2 is installed
520
  try:
521
  import markdown2
522
  except ImportError:
523
  problems.append("markdown2 package is not installed")
524
 
525
- # Check if Groq client can be initialized
526
  try:
527
  client = Groq(api_key=os.getenv("GROQ_API_KEY") or "dummy_key_for_test")
528
  except Exception as e:
@@ -533,7 +433,6 @@ def check_health():
533
  if __name__ == "__main__":
534
  logging.info("Starting Vers3Dynamics Tutor application")
535
 
536
- # Perform health check
537
  health_issues = check_health()
538
  if health_issues:
539
  for issue in health_issues:
@@ -544,14 +443,13 @@ if __name__ == "__main__":
544
  demo = create_interface()
545
  logging.info("Gradio interface created successfully")
546
 
547
- # Launch the app with error handling
548
  try:
549
  logging.info("Launching Gradio server")
550
- demo.queue() # Enable queuing for better handling of concurrent requests
551
  demo.launch(
552
- server_name="0.0.0.0",
553
  server_port=7860,
554
- debug=True # Enable debug mode
555
  )
556
  except Exception as e:
557
  logging.critical(f"Failed to launch Gradio server: {str(e)}")
 
10
  from dotenv import load_dotenv
11
  import markdown2
12
 
13
+ # Set up detailed logging
14
  logging.basicConfig(
15
+ level=logging.DEBUG,
16
  format='%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s',
17
  handlers=[
18
  logging.StreamHandler(sys.stdout),
 
27
  # Print environment check
28
  logging.debug(f"GROQ_API_KEY present: {bool(os.getenv('GROQ_API_KEY'))}")
29
 
30
+ # Initialize Groq client with error handling
31
  try:
32
  api_key = os.getenv("GROQ_API_KEY")
33
  if not api_key:
 
57
 
58
  logging.debug(f"Audio input received: {type(audio)} - {audio}")
59
 
 
60
  audio_path = audio if isinstance(audio, str) else audio
 
61
  logging.debug(f"Audio path: {audio_path}")
62
  logging.debug(f"File exists: {os.path.exists(audio_path) if audio_path else False}")
63
 
 
64
  if audio_path and os.path.exists(audio_path):
65
  with open(audio_path, "rb") as audio_file:
66
  audio_data = audio_file.read()
67
 
68
  logging.debug(f"Audio file opened, size: {len(audio_data)} bytes")
69
 
 
70
  try:
71
  logging.debug("Sending audio to Groq API for transcription")
72
  transcription = client.audio.transcriptions.create(
 
76
 
77
  logging.debug(f"Transcription response received: {transcription}")
78
 
 
79
  if hasattr(transcription, 'text'):
80
  result = transcription.text
81
  logging.debug(f"Transcription text: {result}")
82
  return result
83
  else:
 
84
  result = transcription.get('text', "Transcription succeeded but returned no text")
85
  logging.debug(f"Transcription text (alt format): {result}")
86
  return result
87
  except Exception as e:
88
  logging.error(f"Audio transcription API error: {str(e)}")
 
89
  return f"Audio transcription failed: {str(e)}"
90
  else:
91
  logging.warning(f"Audio file not found at path: {audio_path}")
92
  return "Audio file not found. Please try recording again."
93
  except Exception as e:
94
  logging.error(f"Error in transcription: {str(e)}")
 
95
  return f"Error in transcription: {str(e)}"
96
 
97
  def generate_tutor_output(subject: str, difficulty: str, student_input: str) -> Dict[str, str]:
 
116
  "dna replication": "the process of DNA replication and its importance in cell division",
117
  "climate change": "the causes and effects of climate change, including global warming and its impact on ecosystems"
118
  },
 
119
  }
120
 
 
121
  subject_lower = subject.lower() if subject else "general"
 
 
122
  enhanced_topic = None
123
  for subj, subject_topics in topics.items():
124
  for topic, description in subject_topics.items():
 
129
  if enhanced_topic:
130
  break
131
 
 
132
  if enhanced_topic:
133
  logging.debug(f"Using enhanced topic: {enhanced_topic}")
134
  prompt = f"""
 
160
  Ensure that the content for each key is a single string, with line breaks where appropriate.
161
  """
162
 
163
+ target_model = "llama-3.3-70b-versatile"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  logging.debug(f"Sending prompt to model: {target_model}")
165
 
166
+ completion = client.chat.completions.create(
167
+ messages=[
168
+ {
169
+ "role": "system",
170
+ "content": f"You are the world's best AI tutor, renowned for your ability to explain complex concepts in an engaging, clear, and memorable way. Your expertise in {subject_lower} is unparalleled, and you're adept at tailoring your teaching to {difficulty} level students. Your goal is to not just impart knowledge, but to inspire a love for learning and critical thinking.",
171
+ },
172
+ {
173
+ "role": "user",
174
+ "content": prompt,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  }
176
+ ],
177
+ model=target_model,
178
+ max_tokens=2000,
179
+ )
180
+
181
+ response_content = completion.choices[0].message.content
182
+ logging.debug(f"Received response: {response_content[:100]}...")
183
+
184
+ try:
185
+ result = json.loads(response_content)
186
+ logging.debug("Successfully parsed JSON response")
187
+ except json.JSONDecodeError:
188
+ logging.warning("Failed to parse JSON, using fallback parsing")
189
+ sections = {
190
+ "lesson": "No lesson generated due to parsing error",
191
+ "example": "No example generated due to parsing error",
192
+ "real_world_problem": "No real-world application generated due to parsing error",
193
+ "quiz": "No quiz generated due to parsing error"
194
+ }
195
+ lines = response_content.split('\n')
196
+ current_section = None
197
+ for line in lines:
198
+ line = line.strip()
199
+ if "Lesson:" in line or line.startswith("1."):
200
+ current_section = "lesson"
201
+ sections[current_section] = line.replace("Lesson:", "").replace("1.", "").strip() + "\n"
202
+ elif "Example:" in line or line.startswith("2."):
203
+ current_section = "example"
204
+ sections[current_section] = line.replace("Example:", "").replace("2.", "").strip() + "\n"
205
+ elif "Real-World Application:" in line or line.startswith("3."):
206
+ current_section = "real_world_problem"
207
+ sections[current_section] = line.replace("Real-World Application:", "").replace("3.", "").strip() + "\n"
208
+ elif "Quiz:" in line or line.startswith("4."):
209
+ current_section = "quiz"
210
+ sections[current_section] = line.replace("Quiz:", "").replace("4.", "").strip() + "\n"
211
+ elif current_section:
212
+ sections[current_section] += line + "\n"
213
+ result = sections
214
+
215
+ # Ensure all keys are present
216
+ for key in ["lesson", "example", "real_world_problem", "quiz"]:
217
+ if key not in result:
218
+ result[key] = f"No {key.replace('_', ' ')} provided"
219
+
220
+ return result
221
+
222
  except Exception as e:
223
  logging.error(f"Error in generate_tutor_output: {str(e)}")
224
  logging.error(traceback.format_exc())
225
+ return {
226
+ "lesson": f"Error: {str(e)}",
227
+ "example": "",
228
+ "real_world_problem": "",
229
+ "quiz": ""
230
+ }
231
 
232
  def process_output(output: Dict[str, Any]) -> Tuple[str, str, str, str]:
233
  """Process the output from generate_tutor_output into HTML format."""
234
  try:
235
  logging.debug(f"Processing output: {str(output)[:100]}...")
236
 
237
+ lesson = markdown2.markdown(output.get("lesson", "No lesson available"))
238
+ example = markdown2.markdown(output.get("example", "No example available"))
239
+ real_world = markdown2.markdown(output.get("real_world_problem", "No real-world application available"))
240
+ quiz = markdown2.markdown(output.get("quiz", "No quiz available"))
 
 
 
 
 
 
241
 
242
  logging.debug("Output processed successfully")
243
  return lesson, example, real_world, quiz
 
253
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
254
  gr.Markdown("# 🎓 Vers3Dynamics Tutor: Your Personal Learning Companion")
255
 
 
256
  state = gr.State({"is_submitting": False})
257
 
258
  with gr.Row():
 
261
  ["Art History", "Computer Science", "Literature", "Math", "Music", "Science", "Social Science"],
262
  label="Subject",
263
  info="Choose the subject of your lesson",
264
+ value="Math"
265
  )
266
  difficulty = gr.Radio(
267
  ["Primary", "Secondary", "Higher Education"],
268
  label="Difficulty Level",
269
  info="Select your proficiency level",
270
+ value="Secondary"
271
  )
272
  student_input = gr.Textbox(
273
  placeholder="Type your topic or question here...",
274
  label="Type Your Question",
275
  info="Enter the topic you want to explore"
276
  )
 
277
  audio_input = gr.Audio(
278
+ type="filepath",
279
  label="Speak Your Question",
280
  sources=["microphone"],
281
+ format="wav"
282
  )
283
 
284
  with gr.Row():
285
  submit_button = gr.Button("📚 Teach Me", variant="primary")
286
  clear_button = gr.Button("🧹 Clear", variant="secondary")
287
 
 
288
  status_indicator = gr.Textbox(
289
  label="Status",
290
  value="Ready",
 
322
  def process_input(subject, difficulty, text_input, audio_input, state):
323
  """Process input from text or audio."""
324
  try:
 
 
 
 
 
 
 
325
  logging.info(f"Received inputs - subject: {subject}, difficulty: {difficulty}")
326
+ logging.info(f"Text input: '{text_input}', Audio input: {audio_input}")
327
 
328
+ subject = subject or "Math"
329
+ difficulty = difficulty or "Secondary"
 
 
330
 
331
+ if not text_input.strip() and not audio_input:
332
+ return (
 
 
 
 
 
 
 
333
  {"is_submitting": False},
334
  "Ready",
335
+ "No input provided",
336
+ "Please provide a question to begin",
337
  "",
338
  "",
339
  ""
340
  )
 
 
 
 
341
 
342
+ if text_input.strip():
 
343
  student_input = text_input.strip()
344
+ transcribed_text = "Using text input"
 
345
  elif audio_input:
 
 
 
346
  transcribed_text = transcribe_audio(audio_input)
347
  student_input = transcribed_text
348
+ if "error" in transcribed_text.lower():
349
+ return (
 
 
 
350
  {"is_submitting": False},
351
  "Ready",
352
  transcribed_text,
353
+ "Transcription error. Please try typing your question.",
354
  "",
355
  "",
356
  ""
357
  )
 
358
  else:
359
+ return (
 
 
360
  {"is_submitting": False},
361
  "Ready",
362
+ "No valid input",
363
+ "Please provide a question",
364
  "",
365
  "",
366
  ""
367
  )
 
 
 
 
368
 
 
369
  tutor_output = generate_tutor_output(subject, difficulty, student_input)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
  lesson, example, real_world, quiz = process_output(tutor_output)
 
 
 
 
371
 
372
+ return (
373
+ {"is_submitting": False},
374
+ "Ready",
375
+ transcribed_text,
376
+ lesson,
377
+ example,
378
+ real_world,
379
+ quiz
380
+ )
381
+
382
  except Exception as e:
383
  logging.error(f"Error in process_input: {str(e)}")
384
  logging.error(traceback.format_exc())
385
+ return (
386
+ {"is_submitting": False},
387
+ "Error",
388
+ f"Error: {str(e)}",
389
+ f"Error processing request: {str(e)}",
390
+ "",
391
+ "",
392
+ ""
393
+ )
394
 
395
  def clear_outputs():
396
  """Clear all inputs and outputs."""
397
  logging.debug("Clearing all outputs")
398
+ return {"is_submitting": False}, "Ready", "", "", "", "", "", ""
399
 
 
400
  submit_button.click(
401
  fn=process_input,
402
  inputs=[subject, difficulty, student_input, audio_input, state],
403
  outputs=[state, status_indicator, transcription_output, lesson_output, example_output, real_world_output, quiz_output]
404
  )
405
 
 
406
  clear_button.click(
407
  fn=clear_outputs,
408
  inputs=[],
 
411
 
412
  return demo
413
 
 
414
  def check_health():
415
  """Perform a health check of required components."""
416
  problems = []
417
 
 
418
  if not os.getenv("GROQ_API_KEY"):
419
  problems.append("GROQ_API_KEY environment variable is not set")
420
 
 
421
  try:
422
  import markdown2
423
  except ImportError:
424
  problems.append("markdown2 package is not installed")
425
 
 
426
  try:
427
  client = Groq(api_key=os.getenv("GROQ_API_KEY") or "dummy_key_for_test")
428
  except Exception as e:
 
433
  if __name__ == "__main__":
434
  logging.info("Starting Vers3Dynamics Tutor application")
435
 
 
436
  health_issues = check_health()
437
  if health_issues:
438
  for issue in health_issues:
 
443
  demo = create_interface()
444
  logging.info("Gradio interface created successfully")
445
 
 
446
  try:
447
  logging.info("Launching Gradio server")
448
+ demo.queue()
449
  demo.launch(
450
+ server_name="0.0.0.0",
451
  server_port=7860,
452
+ debug=True
453
  )
454
  except Exception as e:
455
  logging.critical(f"Failed to launch Gradio server: {str(e)}")