Redfire-1234 commited on
Commit
24d1a81
Β·
verified Β·
1 Parent(s): 4ecc464

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -23
app.py CHANGED
@@ -212,15 +212,71 @@
212
 
213
  # return "\n\n".join(results)
214
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  # # ------------------------------
216
  # # Chapter Detection (Using Actual Chapter Names)
217
  # # ------------------------------
218
  # def detect_chapter_from_list(context, topic, subject):
219
  # """
220
  # Detect chapter using the actual chapter list by matching keywords
 
221
  # """
222
  # if subject not in CHAPTER_NAMES:
223
- # return "Unknown Chapter"
224
 
225
  # chapters = CHAPTER_NAMES[subject]
226
  # combined_text = (topic + " " + context[:1000]).lower()
@@ -258,32 +314,35 @@
258
  # def detect_chapter_with_llm(context, topic, subject, chapters):
259
  # """
260
  # Use LLM to pick the correct chapter from the provided list
 
261
  # """
262
  # if not groq_client:
263
- # return "Unknown Chapter"
264
 
265
  # chapter_list = "\n".join([f"{i+1}. {ch}" for i, ch in enumerate(chapters)])
266
 
267
- # detection_prompt = f"""Based on the following textbook content and topic, identify which chapter from the list below this content belongs to.
268
 
269
  # Topic: {topic}
270
 
271
  # Content snippet:
272
  # {context[:600]}
273
 
274
- # Available chapters:
275
  # {chapter_list}
276
 
277
- # Respond with ONLY the chapter number and name exactly as listed (e.g., "5. Origin and Evolution of Life"). Choose the most relevant chapter.
 
 
278
 
279
- # Chapter:"""
280
 
281
  # try:
282
  # response = groq_client.chat.completions.create(
283
  # messages=[
284
  # {
285
  # "role": "system",
286
- # "content": "You are an expert at identifying which chapter textbook content belongs to. Respond with only the chapter number and name from the provided list."
287
  # },
288
  # {
289
  # "role": "user",
@@ -297,6 +356,11 @@
297
 
298
  # result = response.choices[0].message.content.strip()
299
 
 
 
 
 
 
300
  # # Extract chapter name from response (remove number prefix if present)
301
  # chapter = re.sub(r'^\d+\.\s*', '', result).strip()
302
 
@@ -307,11 +371,11 @@
307
  # return ch
308
 
309
  # print(f"⚠️ LLM response not in list: {result}")
310
- # return chapters[0] # Default to first chapter
311
 
312
  # except Exception as e:
313
  # print(f"⚠️ Chapter detection failed: {e}")
314
- # return "Unknown Chapter"
315
 
316
  # # ------------------------------
317
  # # MCQ Generation
@@ -325,7 +389,7 @@
325
  # 2. API key is valid (get one from https://console.groq.com/keys)
326
  # 3. Space has been restarted after adding the key
327
  # Current status: API key not found or invalid."""
328
- # return error_msg, "Unknown"
329
 
330
  # # Check cache
331
  # context_hash = hashlib.md5(context.encode()).hexdigest()[:8]
@@ -340,6 +404,12 @@
340
  # # Detect the chapter from our actual chapter list
341
  # chapter = detect_chapter_from_list(context, topic, subject)
342
 
 
 
 
 
 
 
343
  # prompt = f"""You are a Class-12 {subject.title()} teacher creating MCQs.
344
  # Topic: "{topic}"
345
  # Chapter: "{chapter}"
@@ -723,8 +793,22 @@
723
  # if subject not in SUBJECTS:
724
  # return jsonify({"error": "Invalid subject"}), 400
725
 
726
- # print(f"\nπŸ” Searching {subject} for: {topic}")
 
 
 
 
 
 
 
 
 
 
 
 
 
727
 
 
728
  # context = rag_search(topic, subject, k=5)
729
 
730
  # if not context or len(context.strip()) < 50:
@@ -732,8 +816,13 @@
732
 
733
  # print(f"βœ“ Context found ({len(context)} chars)")
734
 
 
735
  # mcqs, chapter = generate_mcqs(context, topic, subject)
736
 
 
 
 
 
737
  # return jsonify({
738
  # "mcqs": mcqs,
739
  # "subject": subject,
@@ -761,7 +850,6 @@
761
  # port = int(os.environ.get("PORT", 7860))
762
  # print(f"\nπŸš€ Starting server on port {port}...\n")
763
  # app.run(host="0.0.0.0", port=port, debug=False)
764
-
765
  import pickle
766
  import faiss
767
  from flask import Flask, request, jsonify, render_template_string
@@ -1144,7 +1232,7 @@ Response:"""
1144
  # ------------------------------
1145
  # MCQ Generation
1146
  # ------------------------------
1147
- def generate_mcqs(context, topic, subject):
1148
  # Check if Groq is available
1149
  if not groq_client:
1150
  error_msg = """ERROR: Groq API not initialized!
@@ -1157,13 +1245,13 @@ Current status: API key not found or invalid."""
1157
 
1158
  # Check cache
1159
  context_hash = hashlib.md5(context.encode()).hexdigest()[:8]
1160
- cache_key = get_cache_key(topic, subject, context_hash)
1161
 
1162
  if cache_key in MCQ_CACHE:
1163
  print("βœ“ Using cached MCQs")
1164
  return MCQ_CACHE[cache_key]["mcqs"], MCQ_CACHE[cache_key]["chapter"]
1165
 
1166
- print(f"πŸ€– Generating MCQs for {subject} - {topic}")
1167
 
1168
  # Detect the chapter from our actual chapter list
1169
  chapter = detect_chapter_from_list(context, topic, subject)
@@ -1180,7 +1268,7 @@ Chapter: "{chapter}"
1180
  Reference material from textbook:
1181
  {context[:1500]}
1182
 
1183
- Generate exactly 5 multiple-choice questions based on the reference material.
1184
 
1185
  FORMAT (follow EXACTLY):
1186
  Q1. [Question based on material]
@@ -1197,7 +1285,7 @@ C) [Option 3]
1197
  D) [Option 4]
1198
  Answer: [A/B/C/D] - [Brief explanation]
1199
 
1200
- Continue for Q3, Q4, Q5.
1201
 
1202
  REQUIREMENTS:
1203
  - All questions must be answerable from the reference material
@@ -1205,9 +1293,12 @@ REQUIREMENTS:
1205
  - Correct answer must be clearly supported by material
1206
  - Keep explanations brief (1-2 sentences)
1207
 
1208
- Generate 5 MCQs now:"""
1209
 
1210
  try:
 
 
 
1211
  chat_completion = groq_client.chat.completions.create(
1212
  messages=[
1213
  {
@@ -1221,7 +1312,7 @@ Generate 5 MCQs now:"""
1221
  ],
1222
  model="llama-3.3-70b-versatile",
1223
  temperature=0.3,
1224
- max_tokens=1500,
1225
  top_p=0.9
1226
  )
1227
 
@@ -1449,7 +1540,33 @@ HTML_TEMPLATE = """
1449
  <input type="text" id="topic" placeholder="e.g., Mitochondria, Chemical Bonding, Newton's Laws">
1450
  </div>
1451
 
1452
- <button onclick="generateMCQs()">πŸš€ Generate 5 MCQs</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1453
 
1454
  <div class="loading" id="loading">
1455
  <div class="spinner"></div>
@@ -1479,6 +1596,7 @@ HTML_TEMPLATE = """
1479
  async function generateMCQs() {
1480
  const subject = document.getElementById('subject').value;
1481
  const topic = document.getElementById('topic').value.trim();
 
1482
 
1483
  if (!topic) {
1484
  alert('⚠️ Please enter a topic!');
@@ -1500,7 +1618,7 @@ HTML_TEMPLATE = """
1500
  const response = await fetch('/generate', {
1501
  method: 'POST',
1502
  headers: {'Content-Type': 'application/json'},
1503
- body: JSON.stringify({subject, topic})
1504
  });
1505
 
1506
  const data = await response.json();
@@ -1523,7 +1641,7 @@ HTML_TEMPLATE = """
1523
  } finally {
1524
  loading.classList.remove('show');
1525
  btn.disabled = false;
1526
- btn.textContent = 'πŸš€ Generate 5 MCQs';
1527
  }
1528
  }
1529
 
@@ -1550,6 +1668,15 @@ def generate():
1550
  data = request.json
1551
  subject = data.get("subject", "").lower()
1552
  topic = data.get("topic", "")
 
 
 
 
 
 
 
 
 
1553
 
1554
  if not topic:
1555
  return jsonify({"error": "Topic is required"}), 400
@@ -1581,7 +1708,7 @@ def generate():
1581
  print(f"βœ“ Context found ({len(context)} chars)")
1582
 
1583
  # STEP 3: Generate MCQs
1584
- mcqs, chapter = generate_mcqs(context, topic, subject)
1585
 
1586
  # Check if there was a subject mismatch
1587
  if chapter is None:
 
212
 
213
  # return "\n\n".join(results)
214
 
215
+ # # ------------------------------
216
+ # # Topic Validation (Check if topic belongs to subject)
217
+ # # ------------------------------
218
+ # def validate_topic_subject(topic, subject):
219
+ # """
220
+ # Validate if the topic belongs to the selected subject using LLM
221
+ # Returns True if valid, False otherwise
222
+ # """
223
+ # if not groq_client:
224
+ # return True # Skip validation if API not available
225
+
226
+ # validation_prompt = f"""You are a Class 12 PCB subject expert. Determine if the following topic belongs to {subject.title()}.
227
+
228
+ # Topic: "{topic}"
229
+ # Subject: {subject.title()}
230
+
231
+ # Class 12 {subject.title()} covers:
232
+ # {"- Reproduction, Genetics, Evolution, Plant Physiology, Human Systems, Ecology, Biotechnology" if subject == "biology" else ""}
233
+ # {"- Solid State, Solutions, Thermodynamics, Electrochemistry, Organic Chemistry, Coordination Compounds" if subject == "chemistry" else ""}
234
+ # {"- Rotational Dynamics, Fluids, Thermodynamics, Waves, Optics, Electromagnetism, Modern Physics, Semiconductors" if subject == "physics" else ""}
235
+
236
+ # Answer ONLY with "YES" if the topic belongs to {subject.title()}, or "NO" if it belongs to a different subject.
237
+
238
+ # Answer:"""
239
+
240
+ # try:
241
+ # response = groq_client.chat.completions.create(
242
+ # messages=[
243
+ # {
244
+ # "role": "system",
245
+ # "content": f"You are an expert at identifying which subject a topic belongs to. Answer only YES or NO."
246
+ # },
247
+ # {
248
+ # "role": "user",
249
+ # "content": validation_prompt
250
+ # }
251
+ # ],
252
+ # model="llama-3.3-70b-versatile",
253
+ # temperature=0.1,
254
+ # max_tokens=10
255
+ # )
256
+
257
+ # result = response.choices[0].message.content.strip().upper()
258
+
259
+ # if "YES" in result:
260
+ # print(f"βœ“ Topic '{topic}' validated for {subject}")
261
+ # return True
262
+ # else:
263
+ # print(f"❌ Topic '{topic}' does NOT belong to {subject}")
264
+ # return False
265
+
266
+ # except Exception as e:
267
+ # print(f"⚠️ Validation failed: {e}")
268
+ # return True # Allow on error to avoid blocking
269
+
270
  # # ------------------------------
271
  # # Chapter Detection (Using Actual Chapter Names)
272
  # # ------------------------------
273
  # def detect_chapter_from_list(context, topic, subject):
274
  # """
275
  # Detect chapter using the actual chapter list by matching keywords
276
+ # Returns None if topic doesn't match the subject
277
  # """
278
  # if subject not in CHAPTER_NAMES:
279
+ # return None
280
 
281
  # chapters = CHAPTER_NAMES[subject]
282
  # combined_text = (topic + " " + context[:1000]).lower()
 
314
  # def detect_chapter_with_llm(context, topic, subject, chapters):
315
  # """
316
  # Use LLM to pick the correct chapter from the provided list
317
+ # Also verifies if the topic belongs to the subject
318
  # """
319
  # if not groq_client:
320
+ # return None
321
 
322
  # chapter_list = "\n".join([f"{i+1}. {ch}" for i, ch in enumerate(chapters)])
323
 
324
+ # detection_prompt = f"""Based on the following textbook content and topic, identify which chapter from the Class 12 {subject.title()} textbook this content belongs to.
325
 
326
  # Topic: {topic}
327
 
328
  # Content snippet:
329
  # {context[:600]}
330
 
331
+ # Available {subject.title()} chapters:
332
  # {chapter_list}
333
 
334
+ # IMPORTANT: If the topic and content do NOT belong to {subject.title()}, respond with "NOT_MATCHING".
335
+
336
+ # If it matches, respond with ONLY the chapter number and name exactly as listed (e.g., "5. Origin and Evolution of Life").
337
 
338
+ # Response:"""
339
 
340
  # try:
341
  # response = groq_client.chat.completions.create(
342
  # messages=[
343
  # {
344
  # "role": "system",
345
+ # "content": f"You are an expert at identifying which chapter textbook content belongs to. You can recognize when content doesn't match the subject. If the topic is from a different subject than {subject.title()}, respond with 'NOT_MATCHING'."
346
  # },
347
  # {
348
  # "role": "user",
 
356
 
357
  # result = response.choices[0].message.content.strip()
358
 
359
+ # # Check if topic doesn't match the subject
360
+ # if "NOT_MATCHING" in result.upper() or "NOT MATCHING" in result.upper():
361
+ # print(f"⚠️ Topic '{topic}' doesn't belong to {subject}")
362
+ # return None
363
+
364
  # # Extract chapter name from response (remove number prefix if present)
365
  # chapter = re.sub(r'^\d+\.\s*', '', result).strip()
366
 
 
371
  # return ch
372
 
373
  # print(f"⚠️ LLM response not in list: {result}")
374
+ # return None
375
 
376
  # except Exception as e:
377
  # print(f"⚠️ Chapter detection failed: {e}")
378
+ # return None
379
 
380
  # # ------------------------------
381
  # # MCQ Generation
 
389
  # 2. API key is valid (get one from https://console.groq.com/keys)
390
  # 3. Space has been restarted after adding the key
391
  # Current status: API key not found or invalid."""
392
+ # return error_msg, None
393
 
394
  # # Check cache
395
  # context_hash = hashlib.md5(context.encode()).hexdigest()[:8]
 
404
  # # Detect the chapter from our actual chapter list
405
  # chapter = detect_chapter_from_list(context, topic, subject)
406
 
407
+ # # If chapter is None, topic doesn't belong to this subject
408
+ # if chapter is None:
409
+ # error_msg = f"❌ The topic '{topic}' does not belong to {subject.title()}.\n\nPlease enter a topic related to {subject.title()} or select the correct subject."
410
+ # print(f"⚠️ Topic mismatch: '{topic}' not in {subject}")
411
+ # return error_msg, None
412
+
413
  # prompt = f"""You are a Class-12 {subject.title()} teacher creating MCQs.
414
  # Topic: "{topic}"
415
  # Chapter: "{chapter}"
 
793
  # if subject not in SUBJECTS:
794
  # return jsonify({"error": "Invalid subject"}), 400
795
 
796
+ # print(f"\nπŸ” Validating topic for {subject}...")
797
+
798
+ # # STEP 1: Validate if topic belongs to subject (BEFORE RAG search)
799
+ # if not validate_topic_subject(topic, subject):
800
+ # subject_names = {
801
+ # "biology": "Biology",
802
+ # "chemistry": "Chemistry",
803
+ # "physics": "Physics"
804
+ # }
805
+ # error_msg = f"The topic '{topic}' does not appear to be related to {subject_names[subject]}.\n\nPlease either:\nβ€’ Enter a {subject_names[subject]}-related topic, or\nβ€’ Select the correct subject for this topic"
806
+ # return jsonify({"error": error_msg}), 400
807
+
808
+ # print(f"βœ“ Topic validated for {subject}")
809
+ # print(f"πŸ” Searching {subject} for: {topic}")
810
 
811
+ # # STEP 2: RAG search
812
  # context = rag_search(topic, subject, k=5)
813
 
814
  # if not context or len(context.strip()) < 50:
 
816
 
817
  # print(f"βœ“ Context found ({len(context)} chars)")
818
 
819
+ # # STEP 3: Generate MCQs
820
  # mcqs, chapter = generate_mcqs(context, topic, subject)
821
 
822
+ # # Check if there was a subject mismatch
823
+ # if chapter is None:
824
+ # return jsonify({"error": mcqs}), 400
825
+
826
  # return jsonify({
827
  # "mcqs": mcqs,
828
  # "subject": subject,
 
850
  # port = int(os.environ.get("PORT", 7860))
851
  # print(f"\nπŸš€ Starting server on port {port}...\n")
852
  # app.run(host="0.0.0.0", port=port, debug=False)
 
853
  import pickle
854
  import faiss
855
  from flask import Flask, request, jsonify, render_template_string
 
1232
  # ------------------------------
1233
  # MCQ Generation
1234
  # ------------------------------
1235
+ def generate_mcqs(context, topic, subject, num_questions=5):
1236
  # Check if Groq is available
1237
  if not groq_client:
1238
  error_msg = """ERROR: Groq API not initialized!
 
1245
 
1246
  # Check cache
1247
  context_hash = hashlib.md5(context.encode()).hexdigest()[:8]
1248
+ cache_key = get_cache_key(topic, subject, context_hash) + f":{num_questions}"
1249
 
1250
  if cache_key in MCQ_CACHE:
1251
  print("βœ“ Using cached MCQs")
1252
  return MCQ_CACHE[cache_key]["mcqs"], MCQ_CACHE[cache_key]["chapter"]
1253
 
1254
+ print(f"πŸ€– Generating {num_questions} MCQs for {subject} - {topic}")
1255
 
1256
  # Detect the chapter from our actual chapter list
1257
  chapter = detect_chapter_from_list(context, topic, subject)
 
1268
  Reference material from textbook:
1269
  {context[:1500]}
1270
 
1271
+ Generate exactly {num_questions} multiple-choice questions based on the reference material.
1272
 
1273
  FORMAT (follow EXACTLY):
1274
  Q1. [Question based on material]
 
1285
  D) [Option 4]
1286
  Answer: [A/B/C/D] - [Brief explanation]
1287
 
1288
+ Continue for Q3, Q4, Q5{"..." if num_questions > 5 else ""}.
1289
 
1290
  REQUIREMENTS:
1291
  - All questions must be answerable from the reference material
 
1293
  - Correct answer must be clearly supported by material
1294
  - Keep explanations brief (1-2 sentences)
1295
 
1296
+ Generate {num_questions} MCQs now:"""
1297
 
1298
  try:
1299
+ # Adjust max_tokens based on number of questions
1300
+ max_tokens = min(3000, 300 * num_questions)
1301
+
1302
  chat_completion = groq_client.chat.completions.create(
1303
  messages=[
1304
  {
 
1312
  ],
1313
  model="llama-3.3-70b-versatile",
1314
  temperature=0.3,
1315
+ max_tokens=max_tokens,
1316
  top_p=0.9
1317
  )
1318
 
 
1540
  <input type="text" id="topic" placeholder="e.g., Mitochondria, Chemical Bonding, Newton's Laws">
1541
  </div>
1542
 
1543
+ <div class="form-group">
1544
+ <label for="numQuestions">πŸ”’ Number of MCQs</label>
1545
+ <select id="numQuestions">
1546
+ <option value="1">1 MCQ</option>
1547
+ <option value="2">2 MCQs</option>
1548
+ <option value="3">3 MCQs</option>
1549
+ <option value="4">4 MCQs</option>
1550
+ <option value="5" selected>5 MCQs</option>
1551
+ <option value="6">6 MCQs</option>
1552
+ <option value="7">7 MCQs</option>
1553
+ <option value="8">8 MCQs</option>
1554
+ <option value="9">9 MCQs</option>
1555
+ <option value="10">10 MCQs</option>
1556
+ <option value="11">11 MCQs</option>
1557
+ <option value="12">12 MCQs</option>
1558
+ <option value="13">13 MCQs</option>
1559
+ <option value="14">14 MCQs</option>
1560
+ <option value="15">15 MCQs</option>
1561
+ <option value="16">16 MCQs</option>
1562
+ <option value="17">17 MCQs</option>
1563
+ <option value="18">18 MCQs</option>
1564
+ <option value="19">19 MCQs</option>
1565
+ <option value="20">20 MCQs</option>
1566
+ </select>
1567
+ </div>
1568
+
1569
+ <button onclick="generateMCQs()">πŸš€ Generate MCQs</button>
1570
 
1571
  <div class="loading" id="loading">
1572
  <div class="spinner"></div>
 
1596
  async function generateMCQs() {
1597
  const subject = document.getElementById('subject').value;
1598
  const topic = document.getElementById('topic').value.trim();
1599
+ const numQuestions = parseInt(document.getElementById('numQuestions').value);
1600
 
1601
  if (!topic) {
1602
  alert('⚠️ Please enter a topic!');
 
1618
  const response = await fetch('/generate', {
1619
  method: 'POST',
1620
  headers: {'Content-Type': 'application/json'},
1621
+ body: JSON.stringify({subject, topic, num_questions: numQuestions})
1622
  });
1623
 
1624
  const data = await response.json();
 
1641
  } finally {
1642
  loading.classList.remove('show');
1643
  btn.disabled = false;
1644
+ btn.textContent = 'πŸš€ Generate MCQs';
1645
  }
1646
  }
1647
 
 
1668
  data = request.json
1669
  subject = data.get("subject", "").lower()
1670
  topic = data.get("topic", "")
1671
+ num_questions = data.get("num_questions", 5)
1672
+
1673
+ # Validate num_questions
1674
+ try:
1675
+ num_questions = int(num_questions)
1676
+ if num_questions < 1 or num_questions > 20:
1677
+ num_questions = 5
1678
+ except:
1679
+ num_questions = 5
1680
 
1681
  if not topic:
1682
  return jsonify({"error": "Topic is required"}), 400
 
1708
  print(f"βœ“ Context found ({len(context)} chars)")
1709
 
1710
  # STEP 3: Generate MCQs
1711
+ mcqs, chapter = generate_mcqs(context, topic, subject, num_questions)
1712
 
1713
  # Check if there was a subject mismatch
1714
  if chapter is None: