Update app.py
Browse files
app.py
CHANGED
|
@@ -30,6 +30,7 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(
|
|
| 30 |
# Initialize Groq client
|
| 31 |
try:
|
| 32 |
client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
|
|
|
| 33 |
except Exception as e:
|
| 34 |
logging.error(f"Error initializing Groq client: {str(e)}")
|
| 35 |
raise EnvironmentError("Please set the GROQ_API_KEY environment variable")
|
|
@@ -40,6 +41,7 @@ def transcribe_audio(audio):
|
|
| 40 |
return ""
|
| 41 |
|
| 42 |
audio_path = audio if isinstance(audio, str) else audio.name
|
|
|
|
| 43 |
|
| 44 |
with open(audio_path, "rb") as audio_file:
|
| 45 |
audio_data = audio_file.read()
|
|
@@ -50,6 +52,7 @@ def transcribe_audio(audio):
|
|
| 50 |
response_format="verbose_json",
|
| 51 |
)
|
| 52 |
|
|
|
|
| 53 |
return transcription.text
|
| 54 |
except Exception as e:
|
| 55 |
logging.error(f"Error in transcription: {str(e)}")
|
|
@@ -131,8 +134,9 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
|
|
| 131 |
- Finally, provide the answer starting with "Answer:".
|
| 132 |
3. Real-World Application: A challenging real-world application of this concept, demonstrating its practical use.
|
| 133 |
4. Quiz: Create a short quiz (3 multiple-choice questions) to test the student's understanding.
|
| 134 |
-
Format your entire response as a JSON object with keys: "lesson", "example", "real_world_problem", "quiz".
|
| 135 |
-
|
|
|
|
| 136 |
"""
|
| 137 |
else:
|
| 138 |
prompt = f"""
|
|
@@ -145,11 +149,13 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
|
|
| 145 |
- Finally, provide the answer starting with "Answer:".
|
| 146 |
3. Real-World Application: Describe a real-world problem that can be solved using the concepts from the lesson.
|
| 147 |
4. Quiz: Create a short quiz (3 multiple-choice questions) to test the student's understanding.
|
| 148 |
-
Format your entire response as a JSON object with keys: "lesson", "example", "real_world_problem", "quiz".
|
| 149 |
-
|
|
|
|
| 150 |
"""
|
| 151 |
|
| 152 |
try:
|
|
|
|
| 153 |
completion = client.chat.completions.create(
|
| 154 |
messages=[
|
| 155 |
{
|
|
@@ -164,11 +170,59 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
|
|
| 164 |
model="llama-3.3-70b-versatile",
|
| 165 |
max_tokens=2000,
|
| 166 |
)
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
except Exception as e:
|
| 170 |
logging.error(f"Error generating tutor output: {str(e)}")
|
| 171 |
-
return {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
|
| 173 |
def process_output(output: Dict[str, Any]) -> Tuple[str, str, str, str]:
|
| 174 |
try:
|
|
@@ -179,7 +233,7 @@ def process_output(output: Dict[str, Any]) -> Tuple[str, str, str, str]:
|
|
| 179 |
return lesson, example, real_world, quiz
|
| 180 |
except Exception as e:
|
| 181 |
logging.error(f"Error processing output: {str(e)}")
|
| 182 |
-
return str(e), "", "", ""
|
| 183 |
|
| 184 |
def transcribe_and_display(audio):
|
| 185 |
if not audio:
|
|
@@ -196,12 +250,14 @@ def create_interface() -> gr.Blocks:
|
|
| 196 |
subject = gr.Dropdown(
|
| 197 |
["Art History", "Computer Science", "Literature", "Math", "Music", "Science", "Social Science"],
|
| 198 |
label="Subject",
|
| 199 |
-
info="Choose the subject of your lesson"
|
|
|
|
| 200 |
)
|
| 201 |
difficulty = gr.Radio(
|
| 202 |
["Primary", "Secondary", "Higher Education"],
|
| 203 |
label="Difficulty Level",
|
| 204 |
-
info="Select your proficiency level"
|
|
|
|
| 205 |
)
|
| 206 |
student_input = gr.Textbox(
|
| 207 |
placeholder="Type your topic or question here...",
|
|
@@ -244,33 +300,47 @@ def create_interface() -> gr.Blocks:
|
|
| 244 |
|
| 245 |
def process_input(subject, difficulty, text_input, audio_input, transcribed_text_state):
|
| 246 |
try:
|
| 247 |
-
|
|
|
|
| 248 |
student_input = transcribed_text_state
|
| 249 |
transcribed_output_value = transcribed_text_state
|
| 250 |
-
|
|
|
|
| 251 |
student_input = text_input
|
| 252 |
transcribed_output_value = ""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
|
| 254 |
-
logging.info(f"Processing input: subject={subject}, difficulty={difficulty}
|
| 255 |
|
|
|
|
| 256 |
tutor_output = generate_tutor_output(subject.lower(), difficulty, student_input)
|
|
|
|
|
|
|
| 257 |
lesson, example, real_world, quiz = process_output(tutor_output)
|
|
|
|
|
|
|
| 258 |
return transcribed_output_value, lesson, example, real_world, quiz
|
| 259 |
except Exception as e:
|
| 260 |
logging.error(f"Error in process_input: {str(e)}")
|
| 261 |
-
return str(e), "Error generating lesson", "Error generating example", "Error generating real-world problem", "Error generating quiz"
|
| 262 |
|
| 263 |
def clear_outputs():
|
| 264 |
-
return ""
|
| 265 |
|
|
|
|
| 266 |
audio_input.upload(transcribe_and_display, audio_input, [transcription_output, transcribed_text_state])
|
| 267 |
|
|
|
|
| 268 |
submit_button.click(
|
| 269 |
fn=process_input,
|
| 270 |
inputs=[subject, difficulty, student_input, audio_input, transcribed_text_state],
|
| 271 |
outputs=[transcription_output, lesson_output, example_output, real_world_output, quiz_output]
|
| 272 |
)
|
| 273 |
|
|
|
|
| 274 |
clear_button.click(
|
| 275 |
fn=clear_outputs,
|
| 276 |
inputs=[],
|
|
|
|
| 30 |
# Initialize Groq client
|
| 31 |
try:
|
| 32 |
client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
| 33 |
+
logging.info("Groq client initialized successfully")
|
| 34 |
except Exception as e:
|
| 35 |
logging.error(f"Error initializing Groq client: {str(e)}")
|
| 36 |
raise EnvironmentError("Please set the GROQ_API_KEY environment variable")
|
|
|
|
| 41 |
return ""
|
| 42 |
|
| 43 |
audio_path = audio if isinstance(audio, str) else audio.name
|
| 44 |
+
logging.info(f"Transcribing audio from {audio_path}")
|
| 45 |
|
| 46 |
with open(audio_path, "rb") as audio_file:
|
| 47 |
audio_data = audio_file.read()
|
|
|
|
| 52 |
response_format="verbose_json",
|
| 53 |
)
|
| 54 |
|
| 55 |
+
logging.info(f"Transcription successful: {transcription.text[:50]}...")
|
| 56 |
return transcription.text
|
| 57 |
except Exception as e:
|
| 58 |
logging.error(f"Error in transcription: {str(e)}")
|
|
|
|
| 134 |
- Finally, provide the answer starting with "Answer:".
|
| 135 |
3. Real-World Application: A challenging real-world application of this concept, demonstrating its practical use.
|
| 136 |
4. Quiz: Create a short quiz (3 multiple-choice questions) to test the student's understanding.
|
| 137 |
+
Format your entire response as a valid JSON object with ONLY these keys: "lesson", "example", "real_world_problem", "quiz".
|
| 138 |
+
Each value should be a string. DO NOT include any text outside of the JSON structure.
|
| 139 |
+
Your response should parse correctly when passed to json.loads().
|
| 140 |
"""
|
| 141 |
else:
|
| 142 |
prompt = f"""
|
|
|
|
| 149 |
- Finally, provide the answer starting with "Answer:".
|
| 150 |
3. Real-World Application: Describe a real-world problem that can be solved using the concepts from the lesson.
|
| 151 |
4. Quiz: Create a short quiz (3 multiple-choice questions) to test the student's understanding.
|
| 152 |
+
Format your entire response as a valid JSON object with ONLY these keys: "lesson", "example", "real_world_problem", "quiz".
|
| 153 |
+
Each value should be a string. DO NOT include any text outside of the JSON structure.
|
| 154 |
+
Your response should parse correctly when passed to json.loads().
|
| 155 |
"""
|
| 156 |
|
| 157 |
try:
|
| 158 |
+
logging.info(f"Sending request to Groq API for subject: {subject}, difficulty: {difficulty}")
|
| 159 |
completion = client.chat.completions.create(
|
| 160 |
messages=[
|
| 161 |
{
|
|
|
|
| 170 |
model="llama-3.3-70b-versatile",
|
| 171 |
max_tokens=2000,
|
| 172 |
)
|
| 173 |
+
|
| 174 |
+
logging.info("Successfully received response from Groq API")
|
| 175 |
+
|
| 176 |
+
try:
|
| 177 |
+
# Try to parse the JSON response
|
| 178 |
+
raw_content = completion.choices[0].message.content
|
| 179 |
+
logging.info(f"Raw API response preview: {raw_content[:100]}...")
|
| 180 |
+
result = json.loads(raw_content)
|
| 181 |
+
logging.info("Successfully parsed JSON response")
|
| 182 |
+
return result
|
| 183 |
+
except json.JSONDecodeError as json_err:
|
| 184 |
+
# If JSON parsing fails, log the error and return the raw content in a structured format
|
| 185 |
+
logging.error(f"JSON parsing error: {str(json_err)}")
|
| 186 |
+
raw_content = completion.choices[0].message.content
|
| 187 |
+
|
| 188 |
+
# Try to extract content using basic string parsing if JSON fails
|
| 189 |
+
lesson_content = "The model didn't return properly formatted JSON. Here's the response:"
|
| 190 |
+
example_content = "Error processing example."
|
| 191 |
+
real_world_content = "Error processing real-world problem."
|
| 192 |
+
quiz_content = "Error processing quiz."
|
| 193 |
+
|
| 194 |
+
# Try to extract sections using markers
|
| 195 |
+
if "Lesson:" in raw_content:
|
| 196 |
+
lesson_parts = raw_content.split("Lesson:")[1].split("Example:")[0] if "Example:" in raw_content else raw_content.split("Lesson:")[1]
|
| 197 |
+
lesson_content = "Lesson: " + lesson_parts.strip()
|
| 198 |
+
|
| 199 |
+
if "Example:" in raw_content:
|
| 200 |
+
example_parts = raw_content.split("Example:")[1].split("Real-World Application:")[0] if "Real-World Application:" in raw_content else raw_content.split("Example:")[1]
|
| 201 |
+
example_content = "Example: " + example_parts.strip()
|
| 202 |
+
|
| 203 |
+
if "Real-World Application:" in raw_content:
|
| 204 |
+
real_world_parts = raw_content.split("Real-World Application:")[1].split("Quiz:")[0] if "Quiz:" in raw_content else raw_content.split("Real-World Application:")[1]
|
| 205 |
+
real_world_content = "Real-World Application: " + real_world_parts.strip()
|
| 206 |
+
|
| 207 |
+
if "Quiz:" in raw_content:
|
| 208 |
+
quiz_parts = raw_content.split("Quiz:")[1]
|
| 209 |
+
quiz_content = "Quiz: " + quiz_parts.strip()
|
| 210 |
+
|
| 211 |
+
# Return a formatted response that won't cause downstream errors
|
| 212 |
+
return {
|
| 213 |
+
"lesson": lesson_content,
|
| 214 |
+
"example": example_content,
|
| 215 |
+
"real_world_problem": real_world_content,
|
| 216 |
+
"quiz": quiz_content
|
| 217 |
+
}
|
| 218 |
except Exception as e:
|
| 219 |
logging.error(f"Error generating tutor output: {str(e)}")
|
| 220 |
+
return {
|
| 221 |
+
"lesson": f"Failed to generate lesson: {str(e)}",
|
| 222 |
+
"example": "Error: Could not generate example.",
|
| 223 |
+
"real_world_problem": "Error: Could not generate real-world problem.",
|
| 224 |
+
"quiz": "Error: Could not generate quiz."
|
| 225 |
+
}
|
| 226 |
|
| 227 |
def process_output(output: Dict[str, Any]) -> Tuple[str, str, str, str]:
|
| 228 |
try:
|
|
|
|
| 233 |
return lesson, example, real_world, quiz
|
| 234 |
except Exception as e:
|
| 235 |
logging.error(f"Error processing output: {str(e)}")
|
| 236 |
+
return f"Error: {str(e)}", "Error processing example", "Error processing real-world problem", "Error processing quiz"
|
| 237 |
|
| 238 |
def transcribe_and_display(audio):
|
| 239 |
if not audio:
|
|
|
|
| 250 |
subject = gr.Dropdown(
|
| 251 |
["Art History", "Computer Science", "Literature", "Math", "Music", "Science", "Social Science"],
|
| 252 |
label="Subject",
|
| 253 |
+
info="Choose the subject of your lesson",
|
| 254 |
+
value="Math" # Set default value
|
| 255 |
)
|
| 256 |
difficulty = gr.Radio(
|
| 257 |
["Primary", "Secondary", "Higher Education"],
|
| 258 |
label="Difficulty Level",
|
| 259 |
+
info="Select your proficiency level",
|
| 260 |
+
value="Secondary" # Set default value
|
| 261 |
)
|
| 262 |
student_input = gr.Textbox(
|
| 263 |
placeholder="Type your topic or question here...",
|
|
|
|
| 300 |
|
| 301 |
def process_input(subject, difficulty, text_input, audio_input, transcribed_text_state):
|
| 302 |
try:
|
| 303 |
+
# Determine which input to use
|
| 304 |
+
if audio_input and transcribed_text_state:
|
| 305 |
student_input = transcribed_text_state
|
| 306 |
transcribed_output_value = transcribed_text_state
|
| 307 |
+
logging.info(f"Using transcribed audio input: {student_input[:50]}...")
|
| 308 |
+
elif text_input:
|
| 309 |
student_input = text_input
|
| 310 |
transcribed_output_value = ""
|
| 311 |
+
logging.info(f"Using text input: {student_input[:50]}...")
|
| 312 |
+
else:
|
| 313 |
+
logging.warning("No input provided")
|
| 314 |
+
return "No input provided", "Please provide a question either by typing or speaking.", "", "", ""
|
| 315 |
|
| 316 |
+
logging.info(f"Processing input: subject={subject}, difficulty={difficulty}")
|
| 317 |
|
| 318 |
+
# Generate tutor output
|
| 319 |
tutor_output = generate_tutor_output(subject.lower(), difficulty, student_input)
|
| 320 |
+
|
| 321 |
+
# Process the output
|
| 322 |
lesson, example, real_world, quiz = process_output(tutor_output)
|
| 323 |
+
logging.info("Successfully processed tutor output")
|
| 324 |
+
|
| 325 |
return transcribed_output_value, lesson, example, real_world, quiz
|
| 326 |
except Exception as e:
|
| 327 |
logging.error(f"Error in process_input: {str(e)}")
|
| 328 |
+
return str(e), f"Error generating lesson: {str(e)}", "Error generating example", "Error generating real-world problem", "Error generating quiz"
|
| 329 |
|
| 330 |
def clear_outputs():
|
| 331 |
+
return ["", "", "", "", ""] # Five empty strings for all outputs
|
| 332 |
|
| 333 |
+
# Connect the audio input to the transcription function
|
| 334 |
audio_input.upload(transcribe_and_display, audio_input, [transcription_output, transcribed_text_state])
|
| 335 |
|
| 336 |
+
# Connect the submit button
|
| 337 |
submit_button.click(
|
| 338 |
fn=process_input,
|
| 339 |
inputs=[subject, difficulty, student_input, audio_input, transcribed_text_state],
|
| 340 |
outputs=[transcription_output, lesson_output, example_output, real_world_output, quiz_output]
|
| 341 |
)
|
| 342 |
|
| 343 |
+
# Connect the clear button
|
| 344 |
clear_button.click(
|
| 345 |
fn=clear_outputs,
|
| 346 |
inputs=[],
|