Spaces:
Running
Running
mah-diaa
commited on
Commit
Β·
61303c0
1
Parent(s):
31e0198
Remove preloaded quiz data and test data for full application testing
Browse files- Removed load_preloaded_concepts() function and preloaded concepts loading
- Removed create_test_quiz() function and all test quiz data
- Updated user_state initialization to start with empty data
- Removed all using_preloaded_data logic throughout the codebase
- Fixed quiz initialization to start with empty quiz instead of test data
- Now requires full document upload and processing workflow for testing
app.py
CHANGED
|
@@ -11,109 +11,20 @@ from utils.tutor import ask_guiding_question, analyze_student_approach
|
|
| 11 |
from utils.exercise_generator import generate_exercise
|
| 12 |
from utils.llm_client import call_llm
|
| 13 |
|
| 14 |
-
#
|
| 15 |
-
def load_preloaded_concepts():
|
| 16 |
-
"""Load preloaded concepts from JSON file to avoid LLM calls."""
|
| 17 |
-
preloaded_file = Path(__file__).parent / "data" / "preloaded_concepts.json"
|
| 18 |
-
if preloaded_file.exists():
|
| 19 |
-
try:
|
| 20 |
-
with open(preloaded_file, 'r', encoding='utf-8') as f:
|
| 21 |
-
data = json.load(f)
|
| 22 |
-
print(f"β
[PRELOAD] Loaded preloaded concepts: {len(data.get('concepts', []))} concepts, {len(data.get('topics', []))} topics, {len(data.get('key_points', []))} key points")
|
| 23 |
-
return data
|
| 24 |
-
except Exception as e:
|
| 25 |
-
print(f"β οΈ [PRELOAD] Failed to load preloaded concepts: {str(e)}")
|
| 26 |
-
return None
|
| 27 |
-
else:
|
| 28 |
-
print("βΉοΈ [PRELOAD] No preloaded concepts file found, will use LLM extraction")
|
| 29 |
-
return None
|
| 30 |
-
|
| 31 |
-
# Load preloaded data on startup
|
| 32 |
-
preloaded_data = load_preloaded_concepts()
|
| 33 |
-
|
| 34 |
-
# Create test quiz data for testing (option 1 is always correct)
|
| 35 |
-
def create_test_quiz():
|
| 36 |
-
"""Create test quiz data with option 1 as correct answer for each question."""
|
| 37 |
-
return [
|
| 38 |
-
{
|
| 39 |
-
"question": "What is the time complexity of binary search?",
|
| 40 |
-
"type": "mcq",
|
| 41 |
-
"options": [
|
| 42 |
-
"O(log n)", # Option 1 - correct
|
| 43 |
-
"O(n)",
|
| 44 |
-
"O(n log n)",
|
| 45 |
-
"O(1)"
|
| 46 |
-
],
|
| 47 |
-
"correct_answer": "O(log n)",
|
| 48 |
-
"explanation": "Binary search has O(log n) time complexity because it eliminates half of the search space in each iteration."
|
| 49 |
-
},
|
| 50 |
-
{
|
| 51 |
-
"question": "Which data structure follows LIFO (Last In First Out) principle?",
|
| 52 |
-
"type": "mcq",
|
| 53 |
-
"options": [
|
| 54 |
-
"Stack", # Option 1 - correct
|
| 55 |
-
"Queue",
|
| 56 |
-
"Linked List",
|
| 57 |
-
"Tree"
|
| 58 |
-
],
|
| 59 |
-
"correct_answer": "Stack",
|
| 60 |
-
"explanation": "A stack follows the LIFO principle where the last element added is the first one to be removed."
|
| 61 |
-
},
|
| 62 |
-
{
|
| 63 |
-
"question": "What is the result of 2^3 in binary?",
|
| 64 |
-
"type": "mcq",
|
| 65 |
-
"options": [
|
| 66 |
-
"1000", # Option 1 - correct (8 in binary)
|
| 67 |
-
"1010",
|
| 68 |
-
"1100",
|
| 69 |
-
"1110"
|
| 70 |
-
],
|
| 71 |
-
"correct_answer": "1000",
|
| 72 |
-
"explanation": "2^3 = 8, which is 1000 in binary representation."
|
| 73 |
-
},
|
| 74 |
-
{
|
| 75 |
-
"question": "Which sorting algorithm has the best average time complexity?",
|
| 76 |
-
"type": "mcq",
|
| 77 |
-
"options": [
|
| 78 |
-
"Merge Sort", # Option 1 - correct
|
| 79 |
-
"Bubble Sort",
|
| 80 |
-
"Selection Sort",
|
| 81 |
-
"Insertion Sort"
|
| 82 |
-
],
|
| 83 |
-
"correct_answer": "Merge Sort",
|
| 84 |
-
"explanation": "Merge Sort has O(n log n) average time complexity, which is optimal for comparison-based sorting algorithms."
|
| 85 |
-
},
|
| 86 |
-
{
|
| 87 |
-
"question": "What does CPU stand for?",
|
| 88 |
-
"type": "mcq",
|
| 89 |
-
"options": [
|
| 90 |
-
"Central Processing Unit", # Option 1 - correct
|
| 91 |
-
"Computer Processing Unit",
|
| 92 |
-
"Central Program Unit",
|
| 93 |
-
"Computer Program Unit"
|
| 94 |
-
],
|
| 95 |
-
"correct_answer": "Central Processing Unit",
|
| 96 |
-
"explanation": "CPU stands for Central Processing Unit, which is the primary component that executes instructions in a computer."
|
| 97 |
-
}
|
| 98 |
-
]
|
| 99 |
|
| 100 |
# Global state
|
| 101 |
user_state = {
|
| 102 |
-
"concepts":
|
| 103 |
-
"topics":
|
| 104 |
-
"key_points":
|
| 105 |
-
"document_parsed":
|
| 106 |
"learning_style": None,
|
| 107 |
-
"parsed_data":
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
} if preloaded_data else None,
|
| 113 |
-
"current_quiz": create_test_quiz(), # Load test quiz on startup
|
| 114 |
-
"show_quiz_modal": True, # Show quiz modal by default for testing
|
| 115 |
-
"learning_context": "", # User-provided context for better concept extraction
|
| 116 |
-
"using_preloaded_data": bool(preloaded_data) # Flag to indicate preloaded data is being used
|
| 117 |
}
|
| 118 |
|
| 119 |
|
|
@@ -261,23 +172,18 @@ Just tell me what you'd like! π"""
|
|
| 261 |
|
| 262 |
For example: "I want to learn about ARM assembly" or "Teach me recursion" """
|
| 263 |
else:
|
| 264 |
-
# Generate quiz
|
| 265 |
try:
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
question_types=["mcq"],
|
| 277 |
-
document_context=user_state.get("parsed_data", {}).get("text_preview", ""),
|
| 278 |
-
learning_context=learning_context
|
| 279 |
-
)
|
| 280 |
-
|
| 281 |
if questions:
|
| 282 |
# Store quiz in state
|
| 283 |
user_state["current_quiz"] = questions
|
|
@@ -286,7 +192,7 @@ For example: "I want to learn about ARM assembly" or "Teach me recursion" """
|
|
| 286 |
user_state["quiz_trigger_value"] = user_state.get("quiz_trigger_value", 0) + 1
|
| 287 |
# Update the quiz_trigger State component value (this will trigger the change event)
|
| 288 |
# Note: We can't directly update State from here, so we'll use a workaround
|
| 289 |
-
|
| 290 |
response = f"β
**Quiz Generated!** ({len(questions)} questions)\n\nI've created a quiz based on your concepts. Check the quiz panel on the right! π\n\nYou can:\n- Take the quiz interactively\n- Review all questions\n- Generate more questions"
|
| 291 |
else:
|
| 292 |
response = "β οΈ I had trouble generating questions. Could you try again or provide more specific concepts?"
|
|
@@ -337,39 +243,26 @@ Or tell me: "Generate exercise for {main_concept} in {detected_lang}" and I'll d
|
|
| 337 |
user_state.get("topics", [])
|
| 338 |
)
|
| 339 |
try:
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 343 |
|
| 344 |
-
|
|
|
|
|
|
|
|
|
|
| 345 |
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
|
|
|
| 350 |
|
| 351 |
-
|
| 352 |
-
else:
|
| 353 |
-
curriculum = generate_curriculum(
|
| 354 |
-
concept=main_concept,
|
| 355 |
-
language=detected_lang if detected_lang != "general" else "c", # Default to C for assembly/low-level
|
| 356 |
-
starting_level="beginner",
|
| 357 |
-
num_exercises=5,
|
| 358 |
-
generate_all=False
|
| 359 |
-
)
|
| 360 |
-
|
| 361 |
-
curriculum_text = f"# π Learning Curriculum: {main_concept}\n\n"
|
| 362 |
-
curriculum_text += f"**Overview:** {curriculum.get('overview', '')}\n\n"
|
| 363 |
-
curriculum_text += f"**Estimated Time:** {curriculum.get('estimated_total_time_minutes', 0)} minutes\n\n"
|
| 364 |
-
curriculum_text += "## Learning Path:\n\n"
|
| 365 |
-
|
| 366 |
-
for ex in curriculum.get("learning_path", [])[:3]:
|
| 367 |
-
curriculum_text += f"**Exercise {ex.get('exercise_number')}** ({ex.get('difficulty')}):\n"
|
| 368 |
-
for obj in ex.get("learning_objectives", [])[:2]:
|
| 369 |
-
curriculum_text += f"- {obj}\n"
|
| 370 |
-
curriculum_text += "\n"
|
| 371 |
-
|
| 372 |
-
response = curriculum_text + "\nWould you like to see the full curriculum or start with the first exercise?"
|
| 373 |
except Exception as e:
|
| 374 |
response = f"β Error generating curriculum: {str(e)}"
|
| 375 |
|
|
@@ -387,35 +280,23 @@ Tell me a concept or upload a document, and I'll find the best resources for you
|
|
| 387 |
user_state.get("topics", [])
|
| 388 |
)
|
| 389 |
try:
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
]
|
| 401 |
-
else:
|
| 402 |
-
print(f"π§ [MCP TOOL] search_learning_resources_tool called (chat) - concept: {main_concept}, language: {detected_lang}")
|
| 403 |
-
print(f"π [MCP TOOL] search_learning_resources_tool - Searching for: {main_concept}")
|
| 404 |
-
resources = search_learning_resources(
|
| 405 |
-
concept=main_concept,
|
| 406 |
-
language=detected_lang if detected_lang != "general" else "c", # Default to C for assembly/low-level
|
| 407 |
-
resource_type="all",
|
| 408 |
-
max_results=5
|
| 409 |
-
)
|
| 410 |
-
print(f"β
[MCP TOOL] search_learning_resources_tool - Found {len(resources)} resources")
|
| 411 |
-
|
| 412 |
resources_text = f"# π Learning Resources for: {main_concept}\n\n"
|
| 413 |
for i, res in enumerate(resources, 1):
|
| 414 |
resources_text += f"**{i}. {res.get('title', 'Resource')}**\n"
|
| 415 |
if res.get('url'):
|
| 416 |
resources_text += f"π {res['url']}\n"
|
| 417 |
resources_text += f"{res.get('excerpt', '')}\n\n"
|
| 418 |
-
|
| 419 |
response = resources_text
|
| 420 |
except Exception as e:
|
| 421 |
response = f"β Error finding resources: {str(e)}"
|
|
@@ -516,26 +397,7 @@ Provide a helpful, intelligent response. If they're asking a question, answer it
|
|
| 516 |
else:
|
| 517 |
# Initial greeting or subject prompt
|
| 518 |
if any(word in message_lower for word in ["learn", "teach", "help", "want to", "study"]):
|
| 519 |
-
# Extract subject from message
|
| 520 |
-
if user_state.get("using_preloaded_data", False):
|
| 521 |
-
# Use preloaded concepts instead of calling LLM
|
| 522 |
-
concepts = user_state.get("concepts", [])
|
| 523 |
-
subject = concepts[0] if concepts else message_text
|
| 524 |
-
response = f"""π **Great! You want to learn about: {subject}**
|
| 525 |
-
|
| 526 |
-
I've identified these concepts: {', '.join(concepts[:5]) if concepts else subject}
|
| 527 |
-
|
| 528 |
-
**What would you like to do?**
|
| 529 |
-
1. π Generate a quiz to test your understanding
|
| 530 |
-
2. π Create a progressive learning curriculum
|
| 531 |
-
3. π» Generate a programming exercise with starter files and tests
|
| 532 |
-
4. π Find learning resources and tutorials
|
| 533 |
-
5. π¬ Ask me questions (I'll guide you with questions, not answers!)
|
| 534 |
-
|
| 535 |
-
**π‘ Pro Tip:** Check the "π» Programming Challenges" tab to generate complete exercise packages with starter files, tests, and hints!
|
| 536 |
-
|
| 537 |
-
Just tell me what you'd like! π"""
|
| 538 |
-
else:
|
| 539 |
# Extract subject from message
|
| 540 |
try:
|
| 541 |
prompt = f"""Extract the main learning subject/concept from this message: "{message_text}"
|
|
@@ -606,9 +468,8 @@ I can help you learn programming and CS concepts in several ways:
|
|
| 606 |
|
| 607 |
**What would you like to do?** π"""
|
| 608 |
else:
|
| 609 |
-
#
|
| 610 |
-
|
| 611 |
-
try:
|
| 612 |
system_prompt = """You are Gnosis, a friendly and helpful AI learning tutor. You help students learn programming and computer science.
|
| 613 |
|
| 614 |
Be conversational, welcoming, and helpful. Explain what you can do in a friendly way."""
|
|
@@ -633,11 +494,6 @@ I can help you learn programming and CS concepts. Upload a PDF or tell me what y
|
|
| 633 |
except Exception as e:
|
| 634 |
response = """π **Hi! I'm Gnosis, your AI learning tutor!** π
|
| 635 |
|
| 636 |
-
I can help you learn programming and CS concepts. Upload a PDF or tell me what you want to learn! π"""
|
| 637 |
-
else:
|
| 638 |
-
# Using preloaded data - skip LLM
|
| 639 |
-
response = """π **Hi! I'm Gnosis, your AI learning tutor!** π
|
| 640 |
-
|
| 641 |
I can help you learn programming and CS concepts. Upload a PDF or tell me what you want to learn! π"""
|
| 642 |
|
| 643 |
# ChatInterface handles appending to history automatically
|
|
@@ -828,9 +684,8 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 828 |
|
| 829 |
|
| 830 |
# Quiz Popup Modal (shown when quiz is generated) - positioned as floating panel
|
| 831 |
-
# Initialize quiz_data_state with
|
| 832 |
-
|
| 833 |
-
quiz_data_state = gr.State(value=initial_quiz)
|
| 834 |
current_question_idx = gr.State(value=0)
|
| 835 |
quiz_score_state = gr.State(value={"correct": 0, "total": 0})
|
| 836 |
quiz_trigger = gr.State(value=0) # Trigger to update quiz modal when quiz is generated
|
|
@@ -925,7 +780,6 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 925 |
user_state["key_points"] = parsed_data.get("key_points", [])
|
| 926 |
user_state["document_parsed"] = True
|
| 927 |
user_state["parsed_data"] = parsed_data
|
| 928 |
-
user_state["using_preloaded_data"] = False # Override preloaded data with new extraction
|
| 929 |
|
| 930 |
print(f"π [UPLOAD] Extracted: {len(user_state['concepts'])} concepts, {len(user_state['topics'])} topics, {len(user_state['key_points'])} key points")
|
| 931 |
|
|
@@ -961,15 +815,7 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 961 |
return {}, {}, {}, gr.update(), gr.update(), gr.update(), gr.update()
|
| 962 |
|
| 963 |
def quick_generate_quiz():
|
| 964 |
-
"""Generate quiz
|
| 965 |
-
# If we have preloaded data, use test quiz instead of calling LLM
|
| 966 |
-
if user_state.get("using_preloaded_data", False):
|
| 967 |
-
print("π [QUIZ] Using preloaded test quiz data (no LLM call)")
|
| 968 |
-
questions = create_test_quiz()
|
| 969 |
-
user_state["current_quiz"] = questions
|
| 970 |
-
user_state["show_quiz_modal"] = True
|
| 971 |
-
user_state["quiz_trigger_value"] = user_state.get("quiz_trigger_value", 0) + 1
|
| 972 |
-
return f"β
Generated {len(questions)} quiz questions from preloaded data! Check the quiz panel on the right!"
|
| 973 |
|
| 974 |
concepts = user_state.get("concepts", [])
|
| 975 |
if not concepts:
|
|
@@ -1329,16 +1175,14 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1329 |
def load_quiz_to_modal():
|
| 1330 |
"""Load quiz from state into modal."""
|
| 1331 |
quiz = user_state.get("current_quiz")
|
| 1332 |
-
#
|
| 1333 |
if not quiz or len(quiz) == 0:
|
| 1334 |
-
quiz
|
| 1335 |
-
|
| 1336 |
-
print(f"π [QUIZ] Created and loaded test quiz with {len(quiz)} questions")
|
| 1337 |
else:
|
| 1338 |
print(f"π [QUIZ] Loading existing quiz with {len(quiz)} questions")
|
| 1339 |
|
| 1340 |
-
#
|
| 1341 |
-
if False: # Changed to False to always show quiz
|
| 1342 |
return (
|
| 1343 |
gr.update(visible=True, value="**No quiz available yet. Ask me to generate a quiz!**"),
|
| 1344 |
gr.update(visible=False),
|
|
|
|
| 11 |
from utils.exercise_generator import generate_exercise
|
| 12 |
from utils.llm_client import call_llm
|
| 13 |
|
| 14 |
+
# Removed preloaded concepts and test quiz data for full testing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
# Global state
|
| 17 |
user_state = {
|
| 18 |
+
"concepts": [],
|
| 19 |
+
"topics": [],
|
| 20 |
+
"key_points": [],
|
| 21 |
+
"document_parsed": False,
|
| 22 |
"learning_style": None,
|
| 23 |
+
"parsed_data": None,
|
| 24 |
+
"current_quiz": [], # Start with empty quiz
|
| 25 |
+
"show_quiz_modal": False, # Don't show quiz modal by default
|
| 26 |
+
"learning_context": "",
|
| 27 |
+
"using_preloaded_data": False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
}
|
| 29 |
|
| 30 |
|
|
|
|
| 172 |
|
| 173 |
For example: "I want to learn about ARM assembly" or "Teach me recursion" """
|
| 174 |
else:
|
| 175 |
+
# Generate quiz using LLM
|
| 176 |
try:
|
| 177 |
+
learning_context = user_state.get("learning_context", "")
|
| 178 |
+
questions = generate_quiz(
|
| 179 |
+
concepts=user_state["concepts"],
|
| 180 |
+
topics=user_state.get("topics", []),
|
| 181 |
+
num_questions=10,
|
| 182 |
+
question_types=["mcq"],
|
| 183 |
+
document_context=user_state.get("parsed_data", {}).get("text_preview", ""),
|
| 184 |
+
learning_context=learning_context
|
| 185 |
+
)
|
| 186 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
if questions:
|
| 188 |
# Store quiz in state
|
| 189 |
user_state["current_quiz"] = questions
|
|
|
|
| 192 |
user_state["quiz_trigger_value"] = user_state.get("quiz_trigger_value", 0) + 1
|
| 193 |
# Update the quiz_trigger State component value (this will trigger the change event)
|
| 194 |
# Note: We can't directly update State from here, so we'll use a workaround
|
| 195 |
+
|
| 196 |
response = f"β
**Quiz Generated!** ({len(questions)} questions)\n\nI've created a quiz based on your concepts. Check the quiz panel on the right! π\n\nYou can:\n- Take the quiz interactively\n- Review all questions\n- Generate more questions"
|
| 197 |
else:
|
| 198 |
response = "β οΈ I had trouble generating questions. Could you try again or provide more specific concepts?"
|
|
|
|
| 243 |
user_state.get("topics", [])
|
| 244 |
)
|
| 245 |
try:
|
| 246 |
+
curriculum = generate_curriculum(
|
| 247 |
+
concept=main_concept,
|
| 248 |
+
language=detected_lang if detected_lang != "general" else "c", # Default to C for assembly/low-level
|
| 249 |
+
starting_level="beginner",
|
| 250 |
+
num_exercises=5,
|
| 251 |
+
generate_all=False
|
| 252 |
+
)
|
| 253 |
|
| 254 |
+
curriculum_text = f"# π Learning Curriculum: {main_concept}\n\n"
|
| 255 |
+
curriculum_text += f"**Overview:** {curriculum.get('overview', '')}\n\n"
|
| 256 |
+
curriculum_text += f"**Estimated Time:** {curriculum.get('estimated_total_time_minutes', 0)} minutes\n\n"
|
| 257 |
+
curriculum_text += "## Learning Path:\n\n"
|
| 258 |
|
| 259 |
+
for ex in curriculum.get("learning_path", [])[:3]:
|
| 260 |
+
curriculum_text += f"**Exercise {ex.get('exercise_number')}** ({ex.get('difficulty')}):\n"
|
| 261 |
+
for obj in ex.get("learning_objectives", [])[:2]:
|
| 262 |
+
curriculum_text += f"- {obj}\n"
|
| 263 |
+
curriculum_text += "\n"
|
| 264 |
|
| 265 |
+
response = curriculum_text + "\nWould you like to see the full curriculum or start with the first exercise?"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
except Exception as e:
|
| 267 |
response = f"β Error generating curriculum: {str(e)}"
|
| 268 |
|
|
|
|
| 280 |
user_state.get("topics", [])
|
| 281 |
)
|
| 282 |
try:
|
| 283 |
+
print(f"π§ [MCP TOOL] search_learning_resources_tool called (chat) - concept: {main_concept}, language: {detected_lang}")
|
| 284 |
+
print(f"π [MCP TOOL] search_learning_resources_tool - Searching for: {main_concept}")
|
| 285 |
+
resources = search_learning_resources(
|
| 286 |
+
concept=main_concept,
|
| 287 |
+
language=detected_lang if detected_lang != "general" else "c", # Default to C for assembly/low-level
|
| 288 |
+
resource_type="all",
|
| 289 |
+
max_results=5
|
| 290 |
+
)
|
| 291 |
+
print(f"β
[MCP TOOL] search_learning_resources_tool - Found {len(resources)} resources")
|
| 292 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
resources_text = f"# π Learning Resources for: {main_concept}\n\n"
|
| 294 |
for i, res in enumerate(resources, 1):
|
| 295 |
resources_text += f"**{i}. {res.get('title', 'Resource')}**\n"
|
| 296 |
if res.get('url'):
|
| 297 |
resources_text += f"π {res['url']}\n"
|
| 298 |
resources_text += f"{res.get('excerpt', '')}\n\n"
|
| 299 |
+
|
| 300 |
response = resources_text
|
| 301 |
except Exception as e:
|
| 302 |
response = f"β Error finding resources: {str(e)}"
|
|
|
|
| 397 |
else:
|
| 398 |
# Initial greeting or subject prompt
|
| 399 |
if any(word in message_lower for word in ["learn", "teach", "help", "want to", "study"]):
|
| 400 |
+
# Extract subject from message using LLM
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 401 |
# Extract subject from message
|
| 402 |
try:
|
| 403 |
prompt = f"""Extract the main learning subject/concept from this message: "{message_text}"
|
|
|
|
| 468 |
|
| 469 |
**What would you like to do?** π"""
|
| 470 |
else:
|
| 471 |
+
# Use LLM for substantial questions
|
| 472 |
+
try:
|
|
|
|
| 473 |
system_prompt = """You are Gnosis, a friendly and helpful AI learning tutor. You help students learn programming and computer science.
|
| 474 |
|
| 475 |
Be conversational, welcoming, and helpful. Explain what you can do in a friendly way."""
|
|
|
|
| 494 |
except Exception as e:
|
| 495 |
response = """π **Hi! I'm Gnosis, your AI learning tutor!** π
|
| 496 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
I can help you learn programming and CS concepts. Upload a PDF or tell me what you want to learn! π"""
|
| 498 |
|
| 499 |
# ChatInterface handles appending to history automatically
|
|
|
|
| 684 |
|
| 685 |
|
| 686 |
# Quiz Popup Modal (shown when quiz is generated) - positioned as floating panel
|
| 687 |
+
# Initialize quiz_data_state with empty quiz
|
| 688 |
+
quiz_data_state = gr.State(value=[])
|
|
|
|
| 689 |
current_question_idx = gr.State(value=0)
|
| 690 |
quiz_score_state = gr.State(value={"correct": 0, "total": 0})
|
| 691 |
quiz_trigger = gr.State(value=0) # Trigger to update quiz modal when quiz is generated
|
|
|
|
| 780 |
user_state["key_points"] = parsed_data.get("key_points", [])
|
| 781 |
user_state["document_parsed"] = True
|
| 782 |
user_state["parsed_data"] = parsed_data
|
|
|
|
| 783 |
|
| 784 |
print(f"π [UPLOAD] Extracted: {len(user_state['concepts'])} concepts, {len(user_state['topics'])} topics, {len(user_state['key_points'])} key points")
|
| 785 |
|
|
|
|
| 815 |
return {}, {}, {}, gr.update(), gr.update(), gr.update(), gr.update()
|
| 816 |
|
| 817 |
def quick_generate_quiz():
|
| 818 |
+
"""Generate quiz using LLM."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 819 |
|
| 820 |
concepts = user_state.get("concepts", [])
|
| 821 |
if not concepts:
|
|
|
|
| 1175 |
def load_quiz_to_modal():
|
| 1176 |
"""Load quiz from state into modal."""
|
| 1177 |
quiz = user_state.get("current_quiz")
|
| 1178 |
+
# Check if we have a quiz to load
|
| 1179 |
if not quiz or len(quiz) == 0:
|
| 1180 |
+
print("π [QUIZ] No quiz available to load")
|
| 1181 |
+
return [], 0, {"correct": 0, "total": 0}, "No quiz available. Generate a quiz first!", [], gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
|
|
|
| 1182 |
else:
|
| 1183 |
print(f"π [QUIZ] Loading existing quiz with {len(quiz)} questions")
|
| 1184 |
|
| 1185 |
+
# Show quiz if available
|
|
|
|
| 1186 |
return (
|
| 1187 |
gr.update(visible=True, value="**No quiz available yet. Ask me to generate a quiz!**"),
|
| 1188 |
gr.update(visible=False),
|