Redfire-1234 commited on
Commit
860f142
Β·
verified Β·
1 Parent(s): ab33c20

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +667 -15
app.py CHANGED
@@ -1,3 +1,565 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import pickle
2
  import faiss
3
  from flask import Flask, request, jsonify, render_template_string
@@ -153,6 +715,56 @@ def rag_search(query, subject, k=5):
153
 
154
  return "\n\n".join(results)
155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  # ------------------------------
157
  # MCQ Generation
158
  # ------------------------------
@@ -160,14 +772,12 @@ def generate_mcqs(context, topic, subject):
160
  # Check if Groq is available
161
  if not groq_client:
162
  error_msg = """ERROR: Groq API not initialized!
163
-
164
  Please check:
165
  1. GROQ_API_KEY is set in Space Settings β†’ Repository secrets
166
  2. API key is valid (get one from https://console.groq.com/keys)
167
  3. Space has been restarted after adding the key
168
-
169
  Current status: API key not found or invalid."""
170
- return error_msg
171
 
172
  # Check cache
173
  context_hash = hashlib.md5(context.encode()).hexdigest()[:8]
@@ -175,14 +785,16 @@ Current status: API key not found or invalid."""
175
 
176
  if cache_key in MCQ_CACHE:
177
  print("βœ“ Using cached MCQs")
178
- return MCQ_CACHE[cache_key]
179
 
180
  print(f"πŸ€– Generating MCQs for {subject} - {topic}")
181
 
 
 
 
182
  prompt = f"""You are a Class-12 {subject.title()} teacher creating MCQs.
183
-
184
  Topic: "{topic}"
185
-
186
  Reference material from textbook:
187
  {context[:1500]}
188
 
@@ -234,22 +846,21 @@ Generate 5 MCQs now:"""
234
  result = chat_completion.choices[0].message.content.strip()
235
  result = clean_mcq_output(result)
236
 
237
- cache_mcq(cache_key, result)
 
238
 
239
  print("βœ“ MCQs generated successfully")
240
- return result
241
 
242
  except Exception as e:
243
  error_msg = f"""Error calling Groq API: {str(e)}
244
-
245
  Possible causes:
246
  1. Rate limit exceeded (wait a moment)
247
  2. Invalid API key
248
  3. Network issue
249
-
250
  Please try again in a few seconds."""
251
  print(f"❌ Groq API Error: {e}")
252
- return error_msg
253
 
254
  def clean_mcq_output(text):
255
  lines = text.split('\n')
@@ -357,6 +968,27 @@ HTML_TEMPLATE = """
357
  margin-bottom: 20px;
358
  font-size: 1.4em;
359
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  .mcq-content {
361
  background: white;
362
  padding: 25px;
@@ -440,11 +1072,20 @@ HTML_TEMPLATE = """
440
  <div class="loading" id="loading">
441
  <div class="spinner"></div>
442
  <p style="color: #666; font-size: 16px;">Generating MCQs with AI...</p>
443
- <p style="color: #999; font-size: 13px; margin-top: 10px;">⚑ Usually takes 5-10 seconds</p>
444
  </div>
445
 
446
  <div class="result" id="result">
447
  <h3>πŸ“ Generated MCQs:</h3>
 
 
 
 
 
 
 
 
 
448
  <div style="background: #d4edda; padding: 12px; border-radius: 6px; margin-bottom: 15px; color: #155724; font-size: 14px;">
449
  βœ“ <strong>High Quality:</strong> Generated by Llama 3.3 70B via Groq API
450
  </div>
@@ -465,9 +1106,11 @@ HTML_TEMPLATE = """
465
  const loading = document.getElementById('loading');
466
  const result = document.getElementById('result');
467
  const btn = document.querySelector('button');
 
468
 
469
  loading.classList.add('show');
470
  result.classList.remove('show');
 
471
  btn.disabled = true;
472
  btn.textContent = '⏳ Generating...';
473
 
@@ -485,6 +1128,12 @@ HTML_TEMPLATE = """
485
  return;
486
  }
487
 
 
 
 
 
 
 
488
  document.getElementById('mcqContent').textContent = data.mcqs;
489
  result.classList.add('show');
490
  } catch (error) {
@@ -535,9 +1184,13 @@ def generate():
535
 
536
  print(f"βœ“ Context found ({len(context)} chars)")
537
 
538
- mcqs = generate_mcqs(context, topic, subject)
539
 
540
- return jsonify({"mcqs": mcqs, "subject": subject})
 
 
 
 
541
 
542
  except Exception as e:
543
  print(f"❌ Error: {e}")
@@ -560,4 +1213,3 @@ if __name__ == "__main__":
560
  port = int(os.environ.get("PORT", 7860))
561
  print(f"\nπŸš€ Starting server on port {port}...\n")
562
  app.run(host="0.0.0.0", port=port, debug=False)
563
-
 
1
+ # import pickle
2
+ # import faiss
3
+ # from flask import Flask, request, jsonify, render_template_string
4
+ # from sentence_transformers import SentenceTransformer
5
+ # from huggingface_hub import hf_hub_download
6
+ # import hashlib
7
+ # import re
8
+ # import os
9
+ # import sys
10
+
11
+ # # Import Groq
12
+ # try:
13
+ # from groq import Groq
14
+ # GROQ_AVAILABLE = True
15
+ # except ImportError:
16
+ # print("❌ ERROR: groq package not installed!")
17
+ # print("Add 'groq' to requirements.txt")
18
+ # GROQ_AVAILABLE = False
19
+ # sys.exit(1)
20
+
21
+ # app = Flask(__name__)
22
+
23
+ # print("=" * 50)
24
+ # print("STARTING MCQ GENERATOR APP")
25
+ # print("=" * 50)
26
+
27
+ # # ------------------------------
28
+ # # Initialize Groq API Client
29
+ # # ------------------------------
30
+ # print("\nStep 1: Checking Groq API Key...")
31
+ # print("-" * 50)
32
+
33
+ # GROQ_API_KEY = os.environ.get("GROQ_API_KEY", "").strip()
34
+
35
+ # if not GROQ_API_KEY:
36
+ # print("❌ GROQ_API_KEY not found!")
37
+ # print("\nTo fix this:")
38
+ # print("1. Go to: https://console.groq.com/keys")
39
+ # print("2. Create a free API key")
40
+ # print("3. In HuggingFace Space Settings β†’ Repository secrets")
41
+ # print(" Add: Name=GROQ_API_KEY, Value=<your-key>")
42
+ # print("4. Restart your Space")
43
+ # groq_client = None
44
+ # else:
45
+ # print(f"βœ“ GROQ_API_KEY found ({len(GROQ_API_KEY)} chars)")
46
+ # print(f" First 20 chars: {GROQ_API_KEY[:20]}...")
47
+
48
+ # try:
49
+ # groq_client = Groq(api_key=GROQ_API_KEY)
50
+
51
+ # # Test the API
52
+ # print(" Testing API connection...")
53
+ # test = groq_client.chat.completions.create(
54
+ # messages=[{"role": "user", "content": "test"}],
55
+ # model="llama-3.3-70b-versatile",
56
+ # max_tokens=5
57
+ # )
58
+ # print("βœ“ Groq API working!")
59
+
60
+ # except Exception as e:
61
+ # print(f"❌ Groq API initialization failed:")
62
+ # print(f" Error: {str(e)}")
63
+ # groq_client = None
64
+
65
+ # print("-" * 50)
66
+
67
+ # # ------------------------------
68
+ # # Load embedding model (CPU)
69
+ # # ------------------------------
70
+ # print("\nStep 2: Loading embedding model...")
71
+ # embed_model = SentenceTransformer("all-MiniLM-L6-v2")
72
+ # print("βœ“ Embedding model loaded")
73
+
74
+ # # ------------------------------
75
+ # # Download files from Hugging Face
76
+ # # ------------------------------
77
+ # REPO_ID = "Redfire-1234/pcb_tutor"
78
+
79
+ # print("\nStep 3: Downloading subject files...")
80
+ # print("-" * 50)
81
+
82
+ # try:
83
+ # bio_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="bio_chunks.pkl", repo_type="model")
84
+ # faiss_bio_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_bio.bin", repo_type="model")
85
+
86
+ # chem_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="chem_chunks.pkl", repo_type="model")
87
+ # faiss_chem_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_chem.bin", repo_type="model")
88
+
89
+ # phy_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="phy_chunks.pkl", repo_type="model")
90
+ # faiss_phy_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_phy.bin", repo_type="model")
91
+
92
+ # print("βœ“ All files downloaded")
93
+ # except Exception as e:
94
+ # print(f"❌ Error downloading files: {e}")
95
+ # sys.exit(1)
96
+
97
+ # # Load all subjects into memory
98
+ # print("\nStep 4: Loading subject data into memory...")
99
+ # SUBJECTS = {
100
+ # "biology": {
101
+ # "chunks": pickle.load(open(bio_chunks_path, "rb")),
102
+ # "index": faiss.read_index(faiss_bio_path)
103
+ # },
104
+ # "chemistry": {
105
+ # "chunks": pickle.load(open(chem_chunks_path, "rb")),
106
+ # "index": faiss.read_index(faiss_chem_path)
107
+ # },
108
+ # "physics": {
109
+ # "chunks": pickle.load(open(phy_chunks_path, "rb")),
110
+ # "index": faiss.read_index(faiss_phy_path)
111
+ # }
112
+ # }
113
+
114
+ # print(f"βœ“ Biology: {len(SUBJECTS['biology']['chunks'])} chunks")
115
+ # print(f"βœ“ Chemistry: {len(SUBJECTS['chemistry']['chunks'])} chunks")
116
+ # print(f"βœ“ Physics: {len(SUBJECTS['physics']['chunks'])} chunks")
117
+
118
+ # print("\n" + "=" * 50)
119
+ # print("βœ“ ALL SYSTEMS READY!")
120
+ # print("=" * 50 + "\n")
121
+
122
+ # # ------------------------------
123
+ # # Caching
124
+ # # ------------------------------
125
+ # MCQ_CACHE = {}
126
+ # MAX_CACHE_SIZE = 100
127
+
128
+ # def get_cache_key(topic, subject, context_hash):
129
+ # return f"{subject}:{topic}:{context_hash}"
130
+
131
+ # def cache_mcq(key, mcqs):
132
+ # if len(MCQ_CACHE) >= MAX_CACHE_SIZE:
133
+ # MCQ_CACHE.pop(next(iter(MCQ_CACHE)))
134
+ # MCQ_CACHE[key] = mcqs
135
+
136
+ # # ------------------------------
137
+ # # RAG Search
138
+ # # ------------------------------
139
+ # def rag_search(query, subject, k=5):
140
+ # if subject not in SUBJECTS:
141
+ # return None
142
+
143
+ # chunks = SUBJECTS[subject]["chunks"]
144
+ # index = SUBJECTS[subject]["index"]
145
+
146
+ # q_emb = embed_model.encode([query], show_progress_bar=False).astype("float32")
147
+ # D, I = index.search(q_emb, k)
148
+
149
+ # results = []
150
+ # for idx in I[0]:
151
+ # if idx < len(chunks):
152
+ # results.append(chunks[idx])
153
+
154
+ # return "\n\n".join(results)
155
+
156
+ # # ------------------------------
157
+ # # MCQ Generation
158
+ # # ------------------------------
159
+ # def generate_mcqs(context, topic, subject):
160
+ # # Check if Groq is available
161
+ # if not groq_client:
162
+ # error_msg = """ERROR: Groq API not initialized!
163
+
164
+ # Please check:
165
+ # 1. GROQ_API_KEY is set in Space Settings β†’ Repository secrets
166
+ # 2. API key is valid (get one from https://console.groq.com/keys)
167
+ # 3. Space has been restarted after adding the key
168
+
169
+ # Current status: API key not found or invalid."""
170
+ # return error_msg
171
+
172
+ # # Check cache
173
+ # context_hash = hashlib.md5(context.encode()).hexdigest()[:8]
174
+ # cache_key = get_cache_key(topic, subject, context_hash)
175
+
176
+ # if cache_key in MCQ_CACHE:
177
+ # print("βœ“ Using cached MCQs")
178
+ # return MCQ_CACHE[cache_key]
179
+
180
+ # print(f"πŸ€– Generating MCQs for {subject} - {topic}")
181
+
182
+ # prompt = f"""You are a Class-12 {subject.title()} teacher creating MCQs.
183
+
184
+ # Topic: "{topic}"
185
+
186
+ # Reference material from textbook:
187
+ # {context[:1500]}
188
+
189
+ # Generate exactly 5 multiple-choice questions based on the reference material.
190
+
191
+ # FORMAT (follow EXACTLY):
192
+ # Q1. [Question based on material]
193
+ # A) [Option 1]
194
+ # B) [Option 2]
195
+ # C) [Option 3]
196
+ # D) [Option 4]
197
+ # Answer: [A/B/C/D] - [Brief explanation]
198
+
199
+ # Q2. [Question based on material]
200
+ # A) [Option 1]
201
+ # B) [Option 2]
202
+ # C) [Option 3]
203
+ # D) [Option 4]
204
+ # Answer: [A/B/C/D] - [Brief explanation]
205
+
206
+ # Continue for Q3, Q4, Q5.
207
+
208
+ # REQUIREMENTS:
209
+ # - All questions must be answerable from the reference material
210
+ # - All 4 options should be plausible
211
+ # - Correct answer must be clearly supported by material
212
+ # - Keep explanations brief (1-2 sentences)
213
+
214
+ # Generate 5 MCQs now:"""
215
+
216
+ # try:
217
+ # chat_completion = groq_client.chat.completions.create(
218
+ # messages=[
219
+ # {
220
+ # "role": "system",
221
+ # "content": "You are an expert Class-12 teacher who creates high-quality MCQs from textbook content. You always follow the exact format specified."
222
+ # },
223
+ # {
224
+ # "role": "user",
225
+ # "content": prompt
226
+ # }
227
+ # ],
228
+ # model="llama-3.3-70b-versatile",
229
+ # temperature=0.3,
230
+ # max_tokens=1500,
231
+ # top_p=0.9
232
+ # )
233
+
234
+ # result = chat_completion.choices[0].message.content.strip()
235
+ # result = clean_mcq_output(result)
236
+
237
+ # cache_mcq(cache_key, result)
238
+
239
+ # print("βœ“ MCQs generated successfully")
240
+ # return result
241
+
242
+ # except Exception as e:
243
+ # error_msg = f"""Error calling Groq API: {str(e)}
244
+
245
+ # Possible causes:
246
+ # 1. Rate limit exceeded (wait a moment)
247
+ # 2. Invalid API key
248
+ # 3. Network issue
249
+
250
+ # Please try again in a few seconds."""
251
+ # print(f"❌ Groq API Error: {e}")
252
+ # return error_msg
253
+
254
+ # def clean_mcq_output(text):
255
+ # lines = text.split('\n')
256
+ # cleaned_lines = []
257
+
258
+ # for line in lines:
259
+ # line = line.strip()
260
+
261
+ # if (re.match(r'^Q\d+\.', line) or
262
+ # line.startswith(('A)', 'B)', 'C)', 'D)', 'Answer:', 'Correct Answer:')) or
263
+ # not line):
264
+
265
+ # if line.startswith('Correct Answer:'):
266
+ # line = line.replace('Correct Answer:', 'Answer:')
267
+
268
+ # cleaned_lines.append(line)
269
+
270
+ # return '\n'.join(cleaned_lines)
271
+
272
+ # # ------------------------------
273
+ # # HTML UI
274
+ # # ------------------------------
275
+ # HTML_TEMPLATE = """
276
+ # <!DOCTYPE html>
277
+ # <html>
278
+ # <head>
279
+ # <title>Class 12 PCB MCQ Generator</title>
280
+ # <style>
281
+ # * { margin: 0; padding: 0; box-sizing: border-box; }
282
+ # body {
283
+ # font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
284
+ # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
285
+ # min-height: 100vh;
286
+ # padding: 20px;
287
+ # }
288
+ # .container {
289
+ # max-width: 900px;
290
+ # margin: 0 auto;
291
+ # background: white;
292
+ # border-radius: 20px;
293
+ # box-shadow: 0 20px 60px rgba(0,0,0,0.3);
294
+ # overflow: hidden;
295
+ # }
296
+ # .header {
297
+ # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
298
+ # color: white;
299
+ # padding: 30px;
300
+ # text-align: center;
301
+ # }
302
+ # .header h1 { font-size: 2.5em; margin-bottom: 10px; }
303
+ # .content { padding: 40px; }
304
+ # .form-group { margin-bottom: 25px; }
305
+ # label {
306
+ # display: block;
307
+ # font-weight: 600;
308
+ # margin-bottom: 10px;
309
+ # color: #333;
310
+ # font-size: 16px;
311
+ # }
312
+ # select, input {
313
+ # width: 100%;
314
+ # padding: 15px;
315
+ # border: 2px solid #e0e0e0;
316
+ # border-radius: 10px;
317
+ # font-size: 16px;
318
+ # font-family: inherit;
319
+ # transition: border-color 0.3s;
320
+ # }
321
+ # select:focus, input:focus {
322
+ # outline: none;
323
+ # border-color: #667eea;
324
+ # }
325
+ # button {
326
+ # width: 100%;
327
+ # padding: 18px;
328
+ # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
329
+ # color: white;
330
+ # border: none;
331
+ # border-radius: 10px;
332
+ # font-size: 18px;
333
+ # font-weight: 600;
334
+ # cursor: pointer;
335
+ # transition: all 0.3s;
336
+ # }
337
+ # button:hover {
338
+ # transform: translateY(-2px);
339
+ # box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
340
+ # }
341
+ # button:disabled {
342
+ # background: #ccc;
343
+ # cursor: not-allowed;
344
+ # transform: none;
345
+ # }
346
+ # .result {
347
+ # margin-top: 30px;
348
+ # padding: 25px;
349
+ # background: #f8f9fa;
350
+ # border-radius: 10px;
351
+ # border-left: 4px solid #667eea;
352
+ # display: none;
353
+ # }
354
+ # .result.show { display: block; }
355
+ # .result h3 {
356
+ # color: #667eea;
357
+ # margin-bottom: 20px;
358
+ # font-size: 1.4em;
359
+ # }
360
+ # .mcq-content {
361
+ # background: white;
362
+ # padding: 25px;
363
+ # border-radius: 8px;
364
+ # white-space: pre-wrap;
365
+ # line-height: 1.9;
366
+ # font-size: 15px;
367
+ # }
368
+ # .loading {
369
+ # text-align: center;
370
+ # padding: 30px;
371
+ # display: none;
372
+ # }
373
+ # .loading.show { display: block; }
374
+ # .spinner {
375
+ # border: 4px solid #f3f3f3;
376
+ # border-top: 4px solid #667eea;
377
+ # border-radius: 50%;
378
+ # width: 50px;
379
+ # height: 50px;
380
+ # animation: spin 1s linear infinite;
381
+ # margin: 0 auto 15px;
382
+ # }
383
+ # @keyframes spin {
384
+ # 0% { transform: rotate(0deg); }
385
+ # 100% { transform: rotate(360deg); }
386
+ # }
387
+ # .subject-tag {
388
+ # display: inline-block;
389
+ # padding: 5px 15px;
390
+ # border-radius: 20px;
391
+ # font-size: 13px;
392
+ # font-weight: 600;
393
+ # margin-right: 10px;
394
+ # }
395
+ # .bio { background: #d4edda; color: #155724; }
396
+ # .chem { background: #d1ecf1; color: #0c5460; }
397
+ # .phy { background: #f8d7da; color: #721c24; }
398
+ # .api-badge {
399
+ # background: #17a2b8;
400
+ # color: white;
401
+ # padding: 5px 12px;
402
+ # border-radius: 15px;
403
+ # font-size: 12px;
404
+ # margin-left: 10px;
405
+ # }
406
+ # </style>
407
+ # </head>
408
+ # <body>
409
+ # <div class="container">
410
+ # <div class="header">
411
+ # <h1>πŸŽ“ Class 12 PCB MCQ Generator</h1>
412
+ # <p style="font-size: 1.1em; margin-bottom: 15px;">
413
+ # Generate practice MCQs from your textbooks
414
+ # <span class="api-badge">⚑ Llama 3.3 70B</span>
415
+ # </p>
416
+ # <div>
417
+ # <span class="subject-tag bio">Biology</span>
418
+ # <span class="subject-tag chem">Chemistry</span>
419
+ # <span class="subject-tag phy">Physics</span>
420
+ # </div>
421
+ # </div>
422
+
423
+ # <div class="content">
424
+ # <div class="form-group">
425
+ # <label for="subject">πŸ“š Select Subject</label>
426
+ # <select id="subject">
427
+ # <option value="biology">Biology</option>
428
+ # <option value="chemistry">Chemistry</option>
429
+ # <option value="physics">Physics</option>
430
+ # </select>
431
+ # </div>
432
+
433
+ # <div class="form-group">
434
+ # <label for="topic">✏️ Enter Topic</label>
435
+ # <input type="text" id="topic" placeholder="e.g., Mitochondria, Chemical Bonding, Newton's Laws">
436
+ # </div>
437
+
438
+ # <button onclick="generateMCQs()">πŸš€ Generate 5 MCQs</button>
439
+
440
+ # <div class="loading" id="loading">
441
+ # <div class="spinner"></div>
442
+ # <p style="color: #666; font-size: 16px;">Generating MCQs with AI...</p>
443
+ # <p style="color: #999; font-size: 13px; margin-top: 10px;">⚑ Usually takes 5-10 seconds</p>
444
+ # </div>
445
+
446
+ # <div class="result" id="result">
447
+ # <h3>πŸ“ Generated MCQs:</h3>
448
+ # <div style="background: #d4edda; padding: 12px; border-radius: 6px; margin-bottom: 15px; color: #155724; font-size: 14px;">
449
+ # βœ“ <strong>High Quality:</strong> Generated by Llama 3.3 70B via Groq API
450
+ # </div>
451
+ # <div class="mcq-content" id="mcqContent"></div>
452
+ # </div>
453
+ # </div>
454
+ # </div>
455
+ # <script>
456
+ # async function generateMCQs() {
457
+ # const subject = document.getElementById('subject').value;
458
+ # const topic = document.getElementById('topic').value.trim();
459
+
460
+ # if (!topic) {
461
+ # alert('⚠️ Please enter a topic!');
462
+ # return;
463
+ # }
464
+
465
+ # const loading = document.getElementById('loading');
466
+ # const result = document.getElementById('result');
467
+ # const btn = document.querySelector('button');
468
+
469
+ # loading.classList.add('show');
470
+ # result.classList.remove('show');
471
+ # btn.disabled = true;
472
+ # btn.textContent = '⏳ Generating...';
473
+
474
+ # try {
475
+ # const response = await fetch('/generate', {
476
+ # method: 'POST',
477
+ # headers: {'Content-Type': 'application/json'},
478
+ # body: JSON.stringify({subject, topic})
479
+ # });
480
+
481
+ # const data = await response.json();
482
+
483
+ # if (data.error) {
484
+ # alert('❌ Error: ' + data.error);
485
+ # return;
486
+ # }
487
+
488
+ # document.getElementById('mcqContent').textContent = data.mcqs;
489
+ # result.classList.add('show');
490
+ # } catch (error) {
491
+ # alert('❌ Error: ' + error.message);
492
+ # } finally {
493
+ # loading.classList.remove('show');
494
+ # btn.disabled = false;
495
+ # btn.textContent = 'πŸš€ Generate 5 MCQs';
496
+ # }
497
+ # }
498
+
499
+ # document.getElementById('topic').addEventListener('keypress', function(e) {
500
+ # if (e.key === 'Enter') {
501
+ # generateMCQs();
502
+ # }
503
+ # });
504
+ # </script>
505
+ # </body>
506
+ # </html>
507
+ # """
508
+
509
+ # # ------------------------------
510
+ # # Routes
511
+ # # ------------------------------
512
+ # @app.route("/")
513
+ # def home():
514
+ # return render_template_string(HTML_TEMPLATE)
515
+
516
+ # @app.route("/generate", methods=["POST"])
517
+ # def generate():
518
+ # try:
519
+ # data = request.json
520
+ # subject = data.get("subject", "").lower()
521
+ # topic = data.get("topic", "")
522
+
523
+ # if not topic:
524
+ # return jsonify({"error": "Topic is required"}), 400
525
+
526
+ # if subject not in SUBJECTS:
527
+ # return jsonify({"error": "Invalid subject"}), 400
528
+
529
+ # print(f"\nπŸ” Searching {subject} for: {topic}")
530
+
531
+ # context = rag_search(topic, subject, k=5)
532
+
533
+ # if not context or len(context.strip()) < 50:
534
+ # return jsonify({"error": f"No content found for: {topic}"}), 404
535
+
536
+ # print(f"βœ“ Context found ({len(context)} chars)")
537
+
538
+ # mcqs = generate_mcqs(context, topic, subject)
539
+
540
+ # return jsonify({"mcqs": mcqs, "subject": subject})
541
+
542
+ # except Exception as e:
543
+ # print(f"❌ Error: {e}")
544
+ # import traceback
545
+ # traceback.print_exc()
546
+ # return jsonify({"error": str(e)}), 500
547
+
548
+ # @app.route("/health")
549
+ # def health():
550
+ # return jsonify({
551
+ # "status": "healthy",
552
+ # "groq_available": groq_client is not None,
553
+ # "cache_size": len(MCQ_CACHE)
554
+ # })
555
+
556
+ # # ------------------------------
557
+ # # Run
558
+ # # ------------------------------
559
+ # if __name__ == "__main__":
560
+ # port = int(os.environ.get("PORT", 7860))
561
+ # print(f"\nπŸš€ Starting server on port {port}...\n")
562
+ # app.run(host="0.0.0.0", port=port, debug=False)
563
  import pickle
564
  import faiss
565
  from flask import Flask, request, jsonify, render_template_string
 
715
 
716
  return "\n\n".join(results)
717
 
718
+ # ------------------------------
719
+ # Chapter Detection
720
+ # ------------------------------
721
+ def detect_chapter(context, topic, subject):
722
+ """Detect which chapter the content is from using LLM"""
723
+ if not groq_client:
724
+ return "Unknown Chapter"
725
+
726
+ detection_prompt = f"""Based on the following textbook content from Class 12 {subject.title()}, identify the chapter name/title.
727
+
728
+ Content:
729
+ {context[:800]}
730
+
731
+ Topic searched: {topic}
732
+
733
+ Respond with ONLY the chapter name, nothing else. For example:
734
+ - "Human Reproduction"
735
+ - "Chemical Bonding"
736
+ - "Laws of Motion"
737
+
738
+ Chapter name:"""
739
+
740
+ try:
741
+ response = groq_client.chat.completions.create(
742
+ messages=[
743
+ {
744
+ "role": "system",
745
+ "content": "You are an expert at identifying chapter names from Class 12 NCERT textbooks. Respond with only the chapter name, no additional text."
746
+ },
747
+ {
748
+ "role": "user",
749
+ "content": detection_prompt
750
+ }
751
+ ],
752
+ model="llama-3.3-70b-versatile",
753
+ temperature=0.1,
754
+ max_tokens=50
755
+ )
756
+
757
+ chapter = response.choices[0].message.content.strip()
758
+ # Clean up the response
759
+ chapter = chapter.replace('"', '').replace("'", "").strip()
760
+
761
+ print(f"βœ“ Detected chapter: {chapter}")
762
+ return chapter
763
+
764
+ except Exception as e:
765
+ print(f"⚠️ Chapter detection failed: {e}")
766
+ return "Unknown Chapter"
767
+
768
  # ------------------------------
769
  # MCQ Generation
770
  # ------------------------------
 
772
  # Check if Groq is available
773
  if not groq_client:
774
  error_msg = """ERROR: Groq API not initialized!
 
775
  Please check:
776
  1. GROQ_API_KEY is set in Space Settings β†’ Repository secrets
777
  2. API key is valid (get one from https://console.groq.com/keys)
778
  3. Space has been restarted after adding the key
 
779
  Current status: API key not found or invalid."""
780
+ return error_msg, "Unknown"
781
 
782
  # Check cache
783
  context_hash = hashlib.md5(context.encode()).hexdigest()[:8]
 
785
 
786
  if cache_key in MCQ_CACHE:
787
  print("βœ“ Using cached MCQs")
788
+ return MCQ_CACHE[cache_key]["mcqs"], MCQ_CACHE[cache_key]["chapter"]
789
 
790
  print(f"πŸ€– Generating MCQs for {subject} - {topic}")
791
 
792
+ # First, detect the chapter
793
+ chapter = detect_chapter(context, topic, subject)
794
+
795
  prompt = f"""You are a Class-12 {subject.title()} teacher creating MCQs.
 
796
  Topic: "{topic}"
797
+ Chapter: "{chapter}"
798
  Reference material from textbook:
799
  {context[:1500]}
800
 
 
846
  result = chat_completion.choices[0].message.content.strip()
847
  result = clean_mcq_output(result)
848
 
849
+ # Cache both MCQs and chapter
850
+ cache_mcq(cache_key, {"mcqs": result, "chapter": chapter})
851
 
852
  print("βœ“ MCQs generated successfully")
853
+ return result, chapter
854
 
855
  except Exception as e:
856
  error_msg = f"""Error calling Groq API: {str(e)}
 
857
  Possible causes:
858
  1. Rate limit exceeded (wait a moment)
859
  2. Invalid API key
860
  3. Network issue
 
861
  Please try again in a few seconds."""
862
  print(f"❌ Groq API Error: {e}")
863
+ return error_msg, "Unknown"
864
 
865
  def clean_mcq_output(text):
866
  lines = text.split('\n')
 
968
  margin-bottom: 20px;
969
  font-size: 1.4em;
970
  }
971
+ .chapter-info {
972
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
973
+ color: white;
974
+ padding: 15px 20px;
975
+ border-radius: 8px;
976
+ margin-bottom: 20px;
977
+ display: flex;
978
+ align-items: center;
979
+ gap: 10px;
980
+ font-size: 16px;
981
+ }
982
+ .chapter-icon {
983
+ font-size: 24px;
984
+ }
985
+ .chapter-text {
986
+ flex: 1;
987
+ }
988
+ .chapter-name {
989
+ font-weight: 700;
990
+ font-size: 18px;
991
+ }
992
  .mcq-content {
993
  background: white;
994
  padding: 25px;
 
1072
  <div class="loading" id="loading">
1073
  <div class="spinner"></div>
1074
  <p style="color: #666; font-size: 16px;">Generating MCQs with AI...</p>
1075
+ <p style="color: #999; font-size: 13px; margin-top: 10px;">⚑ Detecting chapter & creating questions...</p>
1076
  </div>
1077
 
1078
  <div class="result" id="result">
1079
  <h3>πŸ“ Generated MCQs:</h3>
1080
+
1081
+ <div class="chapter-info" id="chapterInfo" style="display: none;">
1082
+ <span class="chapter-icon">πŸ“–</span>
1083
+ <div class="chapter-text">
1084
+ <div style="font-size: 13px; opacity: 0.9;">Chapter:</div>
1085
+ <div class="chapter-name" id="chapterName"></div>
1086
+ </div>
1087
+ </div>
1088
+
1089
  <div style="background: #d4edda; padding: 12px; border-radius: 6px; margin-bottom: 15px; color: #155724; font-size: 14px;">
1090
  βœ“ <strong>High Quality:</strong> Generated by Llama 3.3 70B via Groq API
1091
  </div>
 
1106
  const loading = document.getElementById('loading');
1107
  const result = document.getElementById('result');
1108
  const btn = document.querySelector('button');
1109
+ const chapterInfo = document.getElementById('chapterInfo');
1110
 
1111
  loading.classList.add('show');
1112
  result.classList.remove('show');
1113
+ chapterInfo.style.display = 'none';
1114
  btn.disabled = true;
1115
  btn.textContent = '⏳ Generating...';
1116
 
 
1128
  return;
1129
  }
1130
 
1131
+ // Display chapter info
1132
+ if (data.chapter && data.chapter !== 'Unknown Chapter') {
1133
+ document.getElementById('chapterName').textContent = data.chapter;
1134
+ chapterInfo.style.display = 'flex';
1135
+ }
1136
+
1137
  document.getElementById('mcqContent').textContent = data.mcqs;
1138
  result.classList.add('show');
1139
  } catch (error) {
 
1184
 
1185
  print(f"βœ“ Context found ({len(context)} chars)")
1186
 
1187
+ mcqs, chapter = generate_mcqs(context, topic, subject)
1188
 
1189
+ return jsonify({
1190
+ "mcqs": mcqs,
1191
+ "subject": subject,
1192
+ "chapter": chapter
1193
+ })
1194
 
1195
  except Exception as e:
1196
  print(f"❌ Error: {e}")
 
1213
  port = int(os.environ.get("PORT", 7860))
1214
  print(f"\nπŸš€ Starting server on port {port}...\n")
1215
  app.run(host="0.0.0.0", port=port, debug=False)