Update app.py
Browse files
app.py
CHANGED
|
@@ -30,7 +30,6 @@ 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 |
-
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,18 +40,17 @@ def transcribe_audio(audio):
|
|
| 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()
|
| 48 |
|
|
|
|
| 49 |
transcription = client.audio.transcriptions.create(
|
| 50 |
file=(os.path.basename(audio_path), audio_data),
|
| 51 |
model="distil-whisper-large-v3-en",
|
| 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)}")
|
|
@@ -75,41 +73,7 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
|
|
| 75 |
"dna replication": "the process of DNA replication and its importance in cell division",
|
| 76 |
"climate change": "the causes and effects of climate change, including global warming and its impact on ecosystems"
|
| 77 |
},
|
| 78 |
-
|
| 79 |
-
"renaissance art": "The art and artists of the Renaissance period, including Leonardo da Vinci, Michel angelo, and Raffaello.",
|
| 80 |
-
"ancient egyptian art": "Art forms, techniques, and cultural significance of ancient Egyptian art.",
|
| 81 |
-
"impressionism": "The impressionist movement in art, key artists, and their works.",
|
| 82 |
-
"cubism": "The cubist movement, pioneered by Pablo Picasso and Georges Braque.",
|
| 83 |
-
"modern art": "Art from the late 19th century to the present, including abstract expressionism, pop art, etc."
|
| 84 |
-
},
|
| 85 |
-
"computer science": {
|
| 86 |
-
"algorithms": "Study of algorithms, their design, analysis, and implementation.",
|
| 87 |
-
"data structures": "Different data structures and their applications in computer science.",
|
| 88 |
-
"programming languages": "Overview of various programming languages, their features, and uses.",
|
| 89 |
-
"artificial intelligence": "Basics of AI, machine learning, neural networks, etc.",
|
| 90 |
-
"cybersecurity": "Principles of cybersecurity, threats, and protection mechanisms."
|
| 91 |
-
},
|
| 92 |
-
"literature": {
|
| 93 |
-
"shakespeare": "Works of William Shakespeare, his plays and sonnets.",
|
| 94 |
-
"classic novels": "Notable novels from the 18th, 19th, and early 20th centuries.",
|
| 95 |
-
"modern fiction": "Contemporary novels and their authors.",
|
| 96 |
-
"poetry": "Different forms of poetry and notable poets.",
|
| 97 |
-
"drama": "Theater and dramatic literature."
|
| 98 |
-
},
|
| 99 |
-
"music": {
|
| 100 |
-
"classical music": "Music from the medieval period to the present, focusing on classical compositions.",
|
| 101 |
-
"pop music": "Popular music genres and artists.",
|
| 102 |
-
"jazz": "History and styles of jazz music.",
|
| 103 |
-
"rock and roll": "Evolution of rock music and its influential bands.",
|
| 104 |
-
"music theory": "Fundamentals of music theory, notation, and composition."
|
| 105 |
-
},
|
| 106 |
-
"social science": {
|
| 107 |
-
"economics": "Principles of micro and macroeconomics, economic systems, and policies.",
|
| 108 |
-
"sociology": "Study of society, social behavior, and cultural norms.",
|
| 109 |
-
"psychology": "Human behavior, mental processes, and psychological disorders.",
|
| 110 |
-
"anthropology": "Study of human cultures, evolution, and societies.",
|
| 111 |
-
"geography": "Earth's physical and human features, maps, and spatial analysis."
|
| 112 |
-
}
|
| 113 |
}
|
| 114 |
|
| 115 |
# Check if it's a specific topic and create an enhanced prompt
|
|
@@ -134,9 +98,8 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
|
|
| 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
|
| 138 |
-
|
| 139 |
-
Your response should parse correctly when passed to json.loads().
|
| 140 |
"""
|
| 141 |
else:
|
| 142 |
prompt = f"""
|
|
@@ -149,13 +112,11 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
|
|
| 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
|
| 153 |
-
|
| 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,59 +131,11 @@ def generate_tutor_output(subject: str, difficulty: str, student_input: str) ->
|
|
| 170 |
model="llama-3.3-70b-versatile",
|
| 171 |
max_tokens=2000,
|
| 172 |
)
|
| 173 |
-
|
| 174 |
-
|
| 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,13 +146,7 @@ def process_output(output: Dict[str, Any]) -> Tuple[str, str, str, str]:
|
|
| 233 |
return lesson, example, real_world, quiz
|
| 234 |
except Exception as e:
|
| 235 |
logging.error(f"Error processing output: {str(e)}")
|
| 236 |
-
return
|
| 237 |
-
|
| 238 |
-
def transcribe_and_display(audio):
|
| 239 |
-
if not audio:
|
| 240 |
-
return "", ""
|
| 241 |
-
transcription = transcribe_audio(audio)
|
| 242 |
-
return transcription, transcription
|
| 243 |
|
| 244 |
def create_interface() -> gr.Blocks:
|
| 245 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
@@ -250,14 +157,12 @@ def create_interface() -> gr.Blocks:
|
|
| 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...",
|
|
@@ -265,13 +170,12 @@ def create_interface() -> gr.Blocks:
|
|
| 265 |
info="Enter the topic you want to explore"
|
| 266 |
)
|
| 267 |
audio_input = gr.Audio(type="filepath", label="Speak Your Question")
|
| 268 |
-
transcribed_text_state = gr.State("")
|
| 269 |
-
transcription_output = gr.Textbox(label="Transcribed Audio (if provided)")
|
| 270 |
with gr.Row():
|
| 271 |
submit_button = gr.Button("📚 Teach Me", variant="primary")
|
| 272 |
clear_button = gr.Button("🧹 Clear", variant="secondary")
|
| 273 |
|
| 274 |
with gr.Column(scale=3):
|
|
|
|
| 275 |
lesson_output = gr.HTML(label="Lesson")
|
| 276 |
example_output = gr.HTML(label="Example")
|
| 277 |
real_world_output = gr.HTML(label="Real-World Application")
|
|
@@ -298,49 +202,33 @@ def create_interface() -> gr.Blocks:
|
|
| 298 |
Note: Make sure your browser has permission to access your microphone. If you encounter any issues, try using a different browser or check your device's audio settings.
|
| 299 |
""")
|
| 300 |
|
| 301 |
-
def process_input(subject, difficulty, text_input, audio_input
|
| 302 |
try:
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
student_input =
|
| 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 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
logging.info(f"Processing input: subject={subject}, difficulty={difficulty}")
|
| 317 |
|
| 318 |
-
|
| 319 |
-
tutor_output = generate_tutor_output(subject.lower(), difficulty, student_input)
|
| 320 |
|
| 321 |
-
|
| 322 |
lesson, example, real_world, quiz = process_output(tutor_output)
|
| 323 |
-
|
| 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),
|
| 329 |
|
| 330 |
def clear_outputs():
|
| 331 |
-
return [""
|
| 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
|
| 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=[],
|
|
@@ -348,7 +236,7 @@ def create_interface() -> gr.Blocks:
|
|
| 348 |
)
|
| 349 |
|
| 350 |
return demo
|
| 351 |
-
|
| 352 |
if __name__ == "__main__":
|
| 353 |
demo = create_interface()
|
| 354 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
|
| 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 |
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()
|
| 46 |
|
| 47 |
+
# Transcribe the audio using Distil-Whisper
|
| 48 |
transcription = client.audio.transcriptions.create(
|
| 49 |
file=(os.path.basename(audio_path), audio_data),
|
| 50 |
model="distil-whisper-large-v3-en",
|
| 51 |
response_format="verbose_json",
|
| 52 |
)
|
| 53 |
|
|
|
|
| 54 |
return transcription.text
|
| 55 |
except Exception as e:
|
| 56 |
logging.error(f"Error in transcription: {str(e)}")
|
|
|
|
| 73 |
"dna replication": "the process of DNA replication and its importance in cell division",
|
| 74 |
"climate change": "the causes and effects of climate change, including global warming and its impact on ecosystems"
|
| 75 |
},
|
| 76 |
+
# Add more subjects and topics as needed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
}
|
| 78 |
|
| 79 |
# Check if it's a specific topic and create an enhanced prompt
|
|
|
|
| 98 |
- Finally, provide the answer starting with "Answer:".
|
| 99 |
3. Real-World Application: A challenging real-world application of this concept, demonstrating its practical use.
|
| 100 |
4. Quiz: Create a short quiz (3 multiple-choice questions) to test the student's understanding.
|
| 101 |
+
Format your entire response as a JSON object with keys: "lesson", "example", "real_world_problem", "quiz".
|
| 102 |
+
Ensure that the content for each key is a single string, with line breaks where appropriate.
|
|
|
|
| 103 |
"""
|
| 104 |
else:
|
| 105 |
prompt = f"""
|
|
|
|
| 112 |
- Finally, provide the answer starting with "Answer:".
|
| 113 |
3. Real-World Application: Describe a real-world problem that can be solved using the concepts from the lesson.
|
| 114 |
4. Quiz: Create a short quiz (3 multiple-choice questions) to test the student's understanding.
|
| 115 |
+
Format your entire response as a JSON object with keys: "lesson", "example", "real_world_problem", "quiz".
|
| 116 |
+
Ensure that the content for each key is a single string, with line breaks where appropriate.
|
|
|
|
| 117 |
"""
|
| 118 |
|
| 119 |
try:
|
|
|
|
| 120 |
completion = client.chat.completions.create(
|
| 121 |
messages=[
|
| 122 |
{
|
|
|
|
| 131 |
model="llama-3.3-70b-versatile",
|
| 132 |
max_tokens=2000,
|
| 133 |
)
|
| 134 |
+
# Parse the JSON string into a dictionary before returning
|
| 135 |
+
return json.loads(completion.choices[0].message.content)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
except Exception as e:
|
| 137 |
logging.error(f"Error generating tutor output: {str(e)}")
|
| 138 |
+
return {"error": f"Failed to generate tutor output: {str(e)}"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
def process_output(output: Dict[str, Any]) -> Tuple[str, str, str, str]:
|
| 141 |
try:
|
|
|
|
| 146 |
return lesson, example, real_world, quiz
|
| 147 |
except Exception as e:
|
| 148 |
logging.error(f"Error processing output: {str(e)}")
|
| 149 |
+
return str(e), "", "", ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
def create_interface() -> gr.Blocks:
|
| 152 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
|
|
| 157 |
subject = gr.Dropdown(
|
| 158 |
["Art History", "Computer Science", "Literature", "Math", "Music", "Science", "Social Science"],
|
| 159 |
label="Subject",
|
| 160 |
+
info="Choose the subject of your lesson"
|
|
|
|
| 161 |
)
|
| 162 |
difficulty = gr.Radio(
|
| 163 |
["Primary", "Secondary", "Higher Education"],
|
| 164 |
label="Difficulty Level",
|
| 165 |
+
info="Select your proficiency level"
|
|
|
|
| 166 |
)
|
| 167 |
student_input = gr.Textbox(
|
| 168 |
placeholder="Type your topic or question here...",
|
|
|
|
| 170 |
info="Enter the topic you want to explore"
|
| 171 |
)
|
| 172 |
audio_input = gr.Audio(type="filepath", label="Speak Your Question")
|
|
|
|
|
|
|
| 173 |
with gr.Row():
|
| 174 |
submit_button = gr.Button("📚 Teach Me", variant="primary")
|
| 175 |
clear_button = gr.Button("🧹 Clear", variant="secondary")
|
| 176 |
|
| 177 |
with gr.Column(scale=3):
|
| 178 |
+
transcription_output = gr.Textbox(label="Transcribed Audio (if provided)")
|
| 179 |
lesson_output = gr.HTML(label="Lesson")
|
| 180 |
example_output = gr.HTML(label="Example")
|
| 181 |
real_world_output = gr.HTML(label="Real-World Application")
|
|
|
|
| 202 |
Note: Make sure your browser has permission to access your microphone. If you encounter any issues, try using a different browser or check your device's audio settings.
|
| 203 |
""")
|
| 204 |
|
| 205 |
+
def process_input(subject, difficulty, text_input, audio_input):
|
| 206 |
try:
|
| 207 |
+
if audio_input:
|
| 208 |
+
transcribed_text = transcribe_audio(audio_input)
|
| 209 |
+
student_input = transcribed_text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
else:
|
| 211 |
+
student_input = text_input
|
| 212 |
+
transcribed_text = ""
|
|
|
|
|
|
|
| 213 |
|
| 214 |
+
logging.info(f"Processing input: subject={subject}, difficulty={difficulty}, student_input={student_input}")
|
|
|
|
| 215 |
|
| 216 |
+
tutor_output = generate_tutor_output(subject, difficulty, student_input)
|
| 217 |
lesson, example, real_world, quiz = process_output(tutor_output)
|
| 218 |
+
return transcribed_text, lesson, example, real_world, quiz
|
|
|
|
|
|
|
| 219 |
except Exception as e:
|
| 220 |
logging.error(f"Error in process_input: {str(e)}")
|
| 221 |
+
return str(e), "Error generating lesson", "Error generating example", "Error generating real-world problem", "Error generating quiz"
|
| 222 |
|
| 223 |
def clear_outputs():
|
| 224 |
+
return [""] * 5 # Clear all five output fields
|
| 225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
submit_button.click(
|
| 227 |
fn=process_input,
|
| 228 |
+
inputs=[subject, difficulty, student_input, audio_input],
|
| 229 |
outputs=[transcription_output, lesson_output, example_output, real_world_output, quiz_output]
|
| 230 |
)
|
| 231 |
|
|
|
|
| 232 |
clear_button.click(
|
| 233 |
fn=clear_outputs,
|
| 234 |
inputs=[],
|
|
|
|
| 236 |
)
|
| 237 |
|
| 238 |
return demo
|
| 239 |
+
|
| 240 |
if __name__ == "__main__":
|
| 241 |
demo = create_interface()
|
| 242 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|