Redfire-1234 commited on
Commit
7a7db8c
·
verified ·
1 Parent(s): a08a958

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +4 -1303
app.py CHANGED
@@ -1,895 +1,3 @@
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
- # # Chapter Names (Actual Textbook Chapters)
29
- # # ------------------------------
30
- # CHAPTER_NAMES = {
31
- # "biology": [
32
- # "Reproduction in Lower and Higher Plants",
33
- # "Reproduction in Lower and Higher Animals",
34
- # "Inheritance and Variation",
35
- # "Molecular Basis of Inheritance",
36
- # "Origin and Evolution of Life",
37
- # "Plant Water Relation",
38
- # "Plant Growth and Mineral Nutrition",
39
- # "Respiration and Circulation",
40
- # "Control and Co-ordination",
41
- # "Human Health and Diseases",
42
- # "Enhancement of Food Production",
43
- # "Biotechnology",
44
- # "Organisms and Populations",
45
- # "Ecosystems and Energy Flow",
46
- # "Biodiversity, Conservation and Environmental Issues"
47
- # ],
48
- # "chemistry": [
49
- # "Solid State",
50
- # "Solutions",
51
- # "Ionic Equilibria",
52
- # "Chemical Thermodynamics",
53
- # "Electrochemistry",
54
- # "Chemical Kinetics",
55
- # "Elements of Groups 16, 17 and 18",
56
- # "Transition and Inner transition Elements",
57
- # "Coordination Compounds",
58
- # "Halogen Derivatives",
59
- # "Alcohols, Phenols and Ethers",
60
- # "Aldehydes, Ketones and Carboxylic acids",
61
- # "Amines",
62
- # "Biomolecules",
63
- # "Introduction to Polymer Chemistry",
64
- # "Green Chemistry and Nanochemistry"
65
- # ],
66
- # "physics": [
67
- # "Rotational Dynamics",
68
- # "Mechanical Properties of Fluids",
69
- # "Kinetic Theory of Gases and Radiation",
70
- # "Thermodynamics",
71
- # "Oscillations",
72
- # "Superposition of Waves",
73
- # "Wave Optics",
74
- # "Electrostatics",
75
- # "Current Electricity",
76
- # "Magnetic Fields due to Electric Current",
77
- # "Magnetic Materials",
78
- # "Electromagnetic induction",
79
- # "AC Circuits",
80
- # "Dual Nature of Radiation and Matter",
81
- # "Structure of Atoms and Nuclei",
82
- # "Semiconductor Devices"
83
- # ]
84
- # }
85
-
86
- # # ------------------------------
87
- # # Initialize Groq API Client
88
- # # ------------------------------
89
- # print("\nStep 1: Checking Groq API Key...")
90
- # print("-" * 50)
91
-
92
- # GROQ_API_KEY = os.environ.get("GROQ_API_KEY", "").strip()
93
-
94
- # if not GROQ_API_KEY:
95
- # print("❌ GROQ_API_KEY not found!")
96
- # print("\nTo fix this:")
97
- # print("1. Go to: https://console.groq.com/keys")
98
- # print("2. Create a free API key")
99
- # print("3. In HuggingFace Space Settings → Repository secrets")
100
- # print(" Add: Name=GROQ_API_KEY, Value=<your-key>")
101
- # print("4. Restart your Space")
102
- # groq_client = None
103
- # else:
104
- # print(f"✓ GROQ_API_KEY found ({len(GROQ_API_KEY)} chars)")
105
- # print(f" First 20 chars: {GROQ_API_KEY[:20]}...")
106
-
107
- # try:
108
- # groq_client = Groq(api_key=GROQ_API_KEY)
109
-
110
- # # Test the API
111
- # print(" Testing API connection...")
112
- # test = groq_client.chat.completions.create(
113
- # messages=[{"role": "user", "content": "test"}],
114
- # model="llama-3.3-70b-versatile",
115
- # max_tokens=5
116
- # )
117
- # print("✓ Groq API working!")
118
-
119
- # except Exception as e:
120
- # print(f"❌ Groq API initialization failed:")
121
- # print(f" Error: {str(e)}")
122
- # groq_client = None
123
-
124
- # print("-" * 50)
125
-
126
- # # ------------------------------
127
- # # Load embedding model (CPU)
128
- # # ------------------------------
129
- # print("\nStep 2: Loading embedding model...")
130
- # embed_model = SentenceTransformer("all-MiniLM-L6-v2")
131
- # print("✓ Embedding model loaded")
132
-
133
- # # ------------------------------
134
- # # Download files from Hugging Face
135
- # # ------------------------------
136
- # REPO_ID = "Redfire-1234/pcb_tutor"
137
-
138
- # print("\nStep 3: Downloading subject files...")
139
- # print("-" * 50)
140
-
141
- # try:
142
- # bio_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="bio_chunks.pkl", repo_type="model")
143
- # faiss_bio_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_bio.bin", repo_type="model")
144
-
145
- # chem_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="chem_chunks.pkl", repo_type="model")
146
- # faiss_chem_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_chem.bin", repo_type="model")
147
-
148
- # phy_chunks_path = hf_hub_download(repo_id=REPO_ID, filename="phy_chunks.pkl", repo_type="model")
149
- # faiss_phy_path = hf_hub_download(repo_id=REPO_ID, filename="faiss_phy.bin", repo_type="model")
150
-
151
- # print("✓ All files downloaded")
152
- # except Exception as e:
153
- # print(f"❌ Error downloading files: {e}")
154
- # sys.exit(1)
155
-
156
- # # Load all subjects into memory
157
- # print("\nStep 4: Loading subject data into memory...")
158
- # SUBJECTS = {
159
- # "biology": {
160
- # "chunks": pickle.load(open(bio_chunks_path, "rb")),
161
- # "index": faiss.read_index(faiss_bio_path)
162
- # },
163
- # "chemistry": {
164
- # "chunks": pickle.load(open(chem_chunks_path, "rb")),
165
- # "index": faiss.read_index(faiss_chem_path)
166
- # },
167
- # "physics": {
168
- # "chunks": pickle.load(open(phy_chunks_path, "rb")),
169
- # "index": faiss.read_index(faiss_phy_path)
170
- # }
171
- # }
172
-
173
- # print(f"✓ Biology: {len(SUBJECTS['biology']['chunks'])} chunks")
174
- # print(f"✓ Chemistry: {len(SUBJECTS['chemistry']['chunks'])} chunks")
175
- # print(f"✓ Physics: {len(SUBJECTS['physics']['chunks'])} chunks")
176
-
177
- # print("\n" + "=" * 50)
178
- # print("✓ ALL SYSTEMS READY!")
179
- # print("=" * 50 + "\n")
180
-
181
- # # ------------------------------
182
- # # Caching
183
- # # ------------------------------
184
- # MCQ_CACHE = {}
185
- # MAX_CACHE_SIZE = 100
186
-
187
- # def get_cache_key(topic, subject, context_hash):
188
- # return f"{subject}:{topic}:{context_hash}"
189
-
190
- # def cache_mcq(key, mcqs):
191
- # if len(MCQ_CACHE) >= MAX_CACHE_SIZE:
192
- # MCQ_CACHE.pop(next(iter(MCQ_CACHE)))
193
- # MCQ_CACHE[key] = mcqs
194
-
195
- # # ------------------------------
196
- # # RAG Search
197
- # # ------------------------------
198
- # def rag_search(query, subject, k=5):
199
- # if subject not in SUBJECTS:
200
- # return None
201
-
202
- # chunks = SUBJECTS[subject]["chunks"]
203
- # index = SUBJECTS[subject]["index"]
204
-
205
- # q_emb = embed_model.encode([query], show_progress_bar=False).astype("float32")
206
- # D, I = index.search(q_emb, k)
207
-
208
- # results = []
209
- # for idx in I[0]:
210
- # if idx < len(chunks):
211
- # results.append(chunks[idx])
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()
283
-
284
- # # Score each chapter based on keyword matching
285
- # scores = {}
286
- # for chapter in chapters:
287
- # score = 0
288
- # chapter_words = chapter.lower().split()
289
-
290
- # # Check if chapter words appear in the content
291
- # for word in chapter_words:
292
- # if len(word) > 3: # Ignore small words like "and", "the"
293
- # if word in combined_text:
294
- # score += 1
295
-
296
- # # Bonus if topic is similar to chapter name
297
- # topic_words = topic.lower().split()
298
- # for t_word in topic_words:
299
- # if len(t_word) > 3 and t_word in chapter.lower():
300
- # score += 2
301
-
302
- # if score > 0:
303
- # scores[chapter] = score
304
-
305
- # # Return chapter with highest score
306
- # if scores:
307
- # best_chapter = max(scores.items(), key=lambda x: x[1])[0]
308
- # print(f"✓ Matched chapter: {best_chapter} (score: {scores[best_chapter]})")
309
- # return best_chapter
310
-
311
- # # Fallback: Use LLM to choose from the list
312
- # return detect_chapter_with_llm(context, topic, subject, chapters)
313
-
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",
349
- # "content": detection_prompt
350
- # }
351
- # ],
352
- # model="llama-3.3-70b-versatile",
353
- # temperature=0.1,
354
- # max_tokens=50
355
- # )
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
-
367
- # # Verify it's in our list
368
- # for ch in chapters:
369
- # if ch.lower() in chapter.lower() or chapter.lower() in ch.lower():
370
- # print(f"✓ LLM detected chapter: {ch}")
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
382
- # # ------------------------------
383
- # def generate_mcqs(context, topic, subject, num_questions=5):
384
- # # Check if Groq is available
385
- # if not groq_client:
386
- # error_msg = """ERROR: Groq API not initialized!
387
- # Please check:
388
- # 1. GROQ_API_KEY is set in Space Settings → Repository secrets
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]
396
- # cache_key = get_cache_key(topic, subject, context_hash) + f":{num_questions}"
397
-
398
- # if cache_key in MCQ_CACHE:
399
- # print("✓ Using cached MCQs")
400
- # return MCQ_CACHE[cache_key]["mcqs"], MCQ_CACHE[cache_key]["chapter"]
401
-
402
- # print(f"🤖 Generating {num_questions} MCQs for {subject} - {topic}")
403
-
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}"
416
- # Reference material from textbook:
417
- # {context[:1500]}
418
-
419
- # Generate exactly {num_questions} multiple-choice questions based on the reference material.
420
-
421
- # FORMAT (follow EXACTLY):
422
- # Q1. [Question based on material]
423
- # A) [Option 1]
424
- # B) [Option 2]
425
- # C) [Option 3]
426
- # D) [Option 4]
427
- # Answer: [A/B/C/D] - [Brief explanation]
428
-
429
- # Q2. [Question based on material]
430
- # A) [Option 1]
431
- # B) [Option 2]
432
- # C) [Option 3]
433
- # D) [Option 4]
434
- # Answer: [A/B/C/D] - [Brief explanation]
435
-
436
- # Continue for Q3, Q4, Q5{"..." if num_questions > 5 else ""}.
437
-
438
- # REQUIREMENTS:
439
- # - All questions must be answerable from the reference material
440
- # - All 4 options should be plausible
441
- # - Correct answer must be clearly supported by material
442
- # - Keep explanations brief (1-2 sentences)
443
-
444
- # Generate {num_questions} MCQs now:"""
445
-
446
- # try:
447
- # # Adjust max_tokens based on number of questions
448
- # max_tokens = min(3000, 300 * num_questions)
449
-
450
- # chat_completion = groq_client.chat.completions.create(
451
- # messages=[
452
- # {
453
- # "role": "system",
454
- # "content": "You are an expert Class-12 teacher who creates high-quality MCQs from textbook content. You always follow the exact format specified."
455
- # },
456
- # {
457
- # "role": "user",
458
- # "content": prompt
459
- # }
460
- # ],
461
- # model="llama-3.3-70b-versatile",
462
- # temperature=0.3,
463
- # max_tokens=max_tokens,
464
- # top_p=0.9
465
- # )
466
-
467
- # result = chat_completion.choices[0].message.content.strip()
468
- # result = clean_mcq_output(result)
469
-
470
- # # Cache both MCQs and chapter
471
- # cache_mcq(cache_key, {"mcqs": result, "chapter": chapter})
472
-
473
- # print("✓ MCQs generated successfully")
474
- # return result, chapter
475
-
476
- # except Exception as e:
477
- # error_msg = f"""Error calling Groq API: {str(e)}
478
- # Possible causes:
479
- # 1. Rate limit exceeded (wait a moment)
480
- # 2. Invalid API key
481
- # 3. Network issue
482
- # Please try again in a few seconds."""
483
- # print(f"❌ Groq API Error: {e}")
484
- # return error_msg, chapter
485
-
486
- # def clean_mcq_output(text):
487
- # lines = text.split('\n')
488
- # cleaned_lines = []
489
-
490
- # for line in lines:
491
- # line = line.strip()
492
-
493
- # if (re.match(r'^Q\d+\.', line) or
494
- # line.startswith(('A)', 'B)', 'C)', 'D)', 'Answer:', 'Correct Answer:')) or
495
- # not line):
496
-
497
- # if line.startswith('Correct Answer:'):
498
- # line = line.replace('Correct Answer:', 'Answer:')
499
-
500
- # cleaned_lines.append(line)
501
-
502
- # return '\n'.join(cleaned_lines)
503
-
504
- # # ------------------------------
505
- # # HTML UI
506
- # # ------------------------------
507
- # HTML_TEMPLATE = """
508
- # <!DOCTYPE html>
509
- # <html>
510
- # <head>
511
- # <title>Class 12 PCB MCQ Generator</title>
512
- # <style>
513
- # * { margin: 0; padding: 0; box-sizing: border-box; }
514
- # body {
515
- # font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
516
- # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
517
- # min-height: 100vh;
518
- # padding: 20px;
519
- # }
520
- # .container {
521
- # max-width: 900px;
522
- # margin: 0 auto;
523
- # background: white;
524
- # border-radius: 20px;
525
- # box-shadow: 0 20px 60px rgba(0,0,0,0.3);
526
- # overflow: hidden;
527
- # }
528
- # .header {
529
- # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
530
- # color: white;
531
- # padding: 30px;
532
- # text-align: center;
533
- # }
534
- # .header h1 { font-size: 2.5em; margin-bottom: 10px; }
535
- # .content { padding: 40px; }
536
- # .form-group { margin-bottom: 25px; }
537
- # label {
538
- # display: block;
539
- # font-weight: 600;
540
- # margin-bottom: 10px;
541
- # color: #333;
542
- # font-size: 16px;
543
- # }
544
- # select, input {
545
- # width: 100%;
546
- # padding: 15px;
547
- # border: 2px solid #e0e0e0;
548
- # border-radius: 10px;
549
- # font-size: 16px;
550
- # font-family: inherit;
551
- # transition: border-color 0.3s;
552
- # }
553
- # select:focus, input:focus {
554
- # outline: none;
555
- # border-color: #667eea;
556
- # }
557
- # button {
558
- # width: 100%;
559
- # padding: 18px;
560
- # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
561
- # color: white;
562
- # border: none;
563
- # border-radius: 10px;
564
- # font-size: 18px;
565
- # font-weight: 600;
566
- # cursor: pointer;
567
- # transition: all 0.3s;
568
- # }
569
- # button:hover {
570
- # transform: translateY(-2px);
571
- # box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
572
- # }
573
- # button:disabled {
574
- # background: #ccc;
575
- # cursor: not-allowed;
576
- # transform: none;
577
- # }
578
- # .result {
579
- # margin-top: 30px;
580
- # padding: 25px;
581
- # background: #f8f9fa;
582
- # border-radius: 10px;
583
- # border-left: 4px solid #667eea;
584
- # display: none;
585
- # }
586
- # .result.show { display: block; }
587
- # .result h3 {
588
- # color: #667eea;
589
- # margin-bottom: 20px;
590
- # font-size: 1.4em;
591
- # }
592
- # .chapter-info {
593
- # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
594
- # color: white;
595
- # padding: 15px 20px;
596
- # border-radius: 8px;
597
- # margin-bottom: 20px;
598
- # display: flex;
599
- # align-items: center;
600
- # gap: 10px;
601
- # font-size: 16px;
602
- # }
603
- # .chapter-icon {
604
- # font-size: 24px;
605
- # }
606
- # .chapter-text {
607
- # flex: 1;
608
- # }
609
- # .chapter-name {
610
- # font-weight: 700;
611
- # font-size: 18px;
612
- # }
613
- # .mcq-content {
614
- # background: white;
615
- # padding: 25px;
616
- # border-radius: 8px;
617
- # white-space: pre-wrap;
618
- # line-height: 1.9;
619
- # font-size: 15px;
620
- # }
621
- # .loading {
622
- # text-align: center;
623
- # padding: 30px;
624
- # display: none;
625
- # }
626
- # .loading.show { display: block; }
627
- # .spinner {
628
- # border: 4px solid #f3f3f3;
629
- # border-top: 4px solid #667eea;
630
- # border-radius: 50%;
631
- # width: 50px;
632
- # height: 50px;
633
- # animation: spin 1s linear infinite;
634
- # margin: 0 auto 15px;
635
- # }
636
- # @keyframes spin {
637
- # 0% { transform: rotate(0deg); }
638
- # 100% { transform: rotate(360deg); }
639
- # }
640
- # .subject-tag {
641
- # display: inline-block;
642
- # padding: 5px 15px;
643
- # border-radius: 20px;
644
- # font-size: 13px;
645
- # font-weight: 600;
646
- # margin-right: 10px;
647
- # }
648
- # .bio { background: #d4edda; color: #155724; }
649
- # .chem { background: #d1ecf1; color: #0c5460; }
650
- # .phy { background: #f8d7da; color: #721c24; }
651
- # .api-badge {
652
- # background: #17a2b8;
653
- # color: white;
654
- # padding: 5px 12px;
655
- # border-radius: 15px;
656
- # font-size: 12px;
657
- # margin-left: 10px;
658
- # }
659
- # </style>
660
- # </head>
661
- # <body>
662
- # <div class="container">
663
- # <div class="header">
664
- # <h1>🎓 Class 12 PCB MCQ Generator</h1>
665
- # <p style="font-size: 1.1em; margin-bottom: 15px;">
666
- # Generate practice MCQs from your textbooks
667
- # <span class="api-badge">⚡ Llama 3.3 70B</span>
668
- # </p>
669
- # <div>
670
- # <span class="subject-tag bio">Biology</span>
671
- # <span class="subject-tag chem">Chemistry</span>
672
- # <span class="subject-tag phy">Physics</span>
673
- # </div>
674
- # </div>
675
-
676
- # <div class="content">
677
- # <div class="form-group">
678
- # <label for="subject">📚 Select Subject</label>
679
- # <select id="subject">
680
- # <option value="biology">Biology</option>
681
- # <option value="chemistry">Chemistry</option>
682
- # <option value="physics">Physics</option>
683
- # </select>
684
- # </div>
685
-
686
- # <div class="form-group">
687
- # <label for="topic">✏️ Enter Topic</label>
688
- # <input type="text" id="topic" placeholder="e.g., Mitochondria, Chemical Bonding, Newton's Laws">
689
- # </div>
690
-
691
- # <div class="form-group">
692
- # <label for="numQuestions">🔢 Number of MCQs</label>
693
- # <select id="numQuestions">
694
- # <option value="1">1 MCQ</option>
695
- # <option value="2">2 MCQs</option>
696
- # <option value="3">3 MCQs</option>
697
- # <option value="4">4 MCQs</option>
698
- # <option value="5" selected>5 MCQs</option>
699
- # <option value="6">6 MCQs</option>
700
- # <option value="7">7 MCQs</option>
701
- # <option value="8">8 MCQs</option>
702
- # <option value="9">9 MCQs</option>
703
- # <option value="10">10 MCQs</option>
704
- # <option value="11">11 MCQs</option>
705
- # <option value="12">12 MCQs</option>
706
- # <option value="13">13 MCQs</option>
707
- # <option value="14">14 MCQs</option>
708
- # <option value="15">15 MCQs</option>
709
- # <option value="16">16 MCQs</option>
710
- # <option value="17">17 MCQs</option>
711
- # <option value="18">18 MCQs</option>
712
- # <option value="19">19 MCQs</option>
713
- # <option value="20">20 MCQs</option>
714
- # </select>
715
- # </div>
716
-
717
- # <button onclick="generateMCQs()">🚀 Generate MCQs</button>
718
-
719
- # <div class="loading" id="loading">
720
- # <div class="spinner"></div>
721
- # <p style="color: #666; font-size: 16px;">Generating MCQs with AI...</p>
722
- # <p style="color: #999; font-size: 13px; margin-top: 10px;">⚡ Detecting chapter from textbook...</p>
723
- # </div>
724
-
725
- # <div class="result" id="result">
726
- # <h3>📝 Generated MCQs:</h3>
727
-
728
- # <div class="chapter-info" id="chapterInfo" style="display: none;">
729
- # <span class="chapter-icon">📖</span>
730
- # <div class="chapter-text">
731
- # <div style="font-size: 13px; opacity: 0.9;">Chapter:</div>
732
- # <div class="chapter-name" id="chapterName"></div>
733
- # </div>
734
- # </div>
735
-
736
- # <div style="background: #d4edda; padding: 12px; border-radius: 6px; margin-bottom: 15px; color: #155724; font-size: 14px;">
737
- # ✓ <strong>High Quality:</strong> Generated by Llama 3.3 70B via Groq API
738
- # </div>
739
- # <div class="mcq-content" id="mcqContent"></div>
740
- # </div>
741
- # </div>
742
- # </div>
743
- # <script>
744
- # async function generateMCQs() {
745
- # const subject = document.getElementById('subject').value;
746
- # const topic = document.getElementById('topic').value.trim();
747
- # const numQuestions = parseInt(document.getElementById('numQuestions').value);
748
-
749
- # if (!topic) {
750
- # alert('⚠️ Please enter a topic!');
751
- # return;
752
- # }
753
-
754
- # const loading = document.getElementById('loading');
755
- # const result = document.getElementById('result');
756
- # const btn = document.querySelector('button');
757
- # const chapterInfo = document.getElementById('chapterInfo');
758
-
759
- # loading.classList.add('show');
760
- # result.classList.remove('show');
761
- # chapterInfo.style.display = 'none';
762
- # btn.disabled = true;
763
- # btn.textContent = '⏳ Generating...';
764
-
765
- # try {
766
- # const response = await fetch('/generate', {
767
- # method: 'POST',
768
- # headers: {'Content-Type': 'application/json'},
769
- # body: JSON.stringify({subject, topic, num_questions: numQuestions})
770
- # });
771
-
772
- # const data = await response.json();
773
-
774
- # if (data.error) {
775
- # alert('❌ Error: ' + data.error);
776
- # return;
777
- # }
778
-
779
- # // Display chapter info
780
- # if (data.chapter && data.chapter !== 'Unknown Chapter') {
781
- # document.getElementById('chapterName').textContent = data.chapter;
782
- # chapterInfo.style.display = 'flex';
783
- # }
784
-
785
- # document.getElementById('mcqContent').textContent = data.mcqs;
786
- # result.classList.add('show');
787
- # } catch (error) {
788
- # alert('❌ Error: ' + error.message);
789
- # } finally {
790
- # loading.classList.remove('show');
791
- # btn.disabled = false;
792
- # btn.textContent = '🚀 Generate MCQs';
793
- # }
794
- # }
795
-
796
- # document.getElementById('topic').addEventListener('keypress', function(e) {
797
- # if (e.key === 'Enter') {
798
- # generateMCQs();
799
- # }
800
- # });
801
- # </script>
802
- # </body>
803
- # </html>
804
- # """
805
-
806
- # # ------------------------------
807
- # # Routes
808
- # # ------------------------------
809
- # @app.route("/")
810
- # def home():
811
- # return render_template_string(HTML_TEMPLATE)
812
-
813
- # @app.route("/generate", methods=["POST"])
814
- # def generate():
815
- # try:
816
- # data = request.json
817
- # subject = data.get("subject", "").lower()
818
- # topic = data.get("topic", "")
819
- # num_questions = data.get("num_questions", 5)
820
-
821
- # # Validate num_questions
822
- # try:
823
- # num_questions = int(num_questions)
824
- # if num_questions < 1 or num_questions > 20:
825
- # num_questions = 5
826
- # except:
827
- # num_questions = 5
828
-
829
- # if not topic:
830
- # return jsonify({"error": "Topic is required"}), 400
831
-
832
- # if subject not in SUBJECTS:
833
- # return jsonify({"error": "Invalid subject"}), 400
834
-
835
- # print(f"\n🔍 Validating topic for {subject}...")
836
-
837
- # # STEP 1: Validate if topic belongs to subject (BEFORE RAG search)
838
- # if not validate_topic_subject(topic, subject):
839
- # subject_names = {
840
- # "biology": "Biology",
841
- # "chemistry": "Chemistry",
842
- # "physics": "Physics"
843
- # }
844
- # 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"
845
- # return jsonify({"error": error_msg}), 400
846
-
847
- # print(f"✓ Topic validated for {subject}")
848
- # print(f"🔍 Searching {subject} for: {topic}")
849
-
850
- # # STEP 2: RAG search
851
- # context = rag_search(topic, subject, k=5)
852
-
853
- # if not context or len(context.strip()) < 50:
854
- # return jsonify({"error": f"No content found for: {topic}"}), 404
855
-
856
- # print(f"✓ Context found ({len(context)} chars)")
857
-
858
- # # STEP 3: Generate MCQs
859
- # mcqs, chapter = generate_mcqs(context, topic, subject, num_questions)
860
-
861
- # # Check if there was a subject mismatch
862
- # if chapter is None:
863
- # return jsonify({"error": mcqs}), 400
864
-
865
- # return jsonify({
866
- # "mcqs": mcqs,
867
- # "subject": subject,
868
- # "chapter": chapter
869
- # })
870
-
871
- # except Exception as e:
872
- # print(f"❌ Error: {e}")
873
- # import traceback
874
- # traceback.print_exc()
875
- # return jsonify({"error": str(e)}), 500
876
-
877
- # @app.route("/health")
878
- # def health():
879
- # return jsonify({
880
- # "status": "healthy",
881
- # "groq_available": groq_client is not None,
882
- # "cache_size": len(MCQ_CACHE)
883
- # })
884
-
885
- # # ------------------------------
886
- # # Run
887
- # # ------------------------------
888
- # if __name__ == "__main__":
889
- # port = int(os.environ.get("PORT", 7860))
890
- # print(f"\n🚀 Starting server on port {port}...\n")
891
- # app.run(host="0.0.0.0", port=port, debug=False)
892
-
893
  import pickle
894
  import faiss
895
  from flask import Flask, request, jsonify, render_template_string
@@ -1389,10 +497,9 @@ def clean_mcq_output(text):
1389
  if line.startswith('Correct Answer:'):
1390
  line = line.replace('Correct Answer:', 'Answer:')
1391
 
1392
- # Split Answer and explanation onto separate lines
1393
- if line.startswith('Answer:'):
1394
- # Match pattern: Answer: X) text - explanation
1395
- match = re.match(r'(Answer:\s*[A-D]\))\s*(.+?)(\s*-\s*(.+))?
1396
 
1397
  # ------------------------------
1398
  # HTML UI
@@ -1781,411 +888,5 @@ def health():
1781
  if __name__ == "__main__":
1782
  port = int(os.environ.get("PORT", 7860))
1783
  print(f"\n🚀 Starting server on port {port}...\n")
1784
- app.run(host="0.0.0.0", port=port, debug=False), line)
1785
- if match:
1786
- answer_part = match.group(1) # "Answer: A)"
1787
- option_text = match.group(2) if match.group(2) else "" # The option text
1788
- explanation = match.group(4) if match.group(4) else "" # The explanation after -
1789
-
1790
- if explanation:
1791
- # Put answer with option text on one line, explanation on next
1792
- cleaned_lines.append(f"{answer_part} {option_text}")
1793
- cleaned_lines.append(f"Explanation: {explanation}")
1794
- else:
1795
- cleaned_lines.append(line)
1796
- else:
1797
- cleaned_lines.append(line)
1798
- else:
1799
- cleaned_lines.append(line)
1800
-
1801
- return '\n'.join(cleaned_lines)
1802
 
1803
- # ------------------------------
1804
- # HTML UI
1805
- # ------------------------------
1806
- HTML_TEMPLATE = """
1807
- <!DOCTYPE html>
1808
- <html>
1809
- <head>
1810
- <title>Class 12 PCB MCQ Generator</title>
1811
- <style>
1812
- * { margin: 0; padding: 0; box-sizing: border-box; }
1813
- body {
1814
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
1815
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1816
- min-height: 100vh;
1817
- padding: 20px;
1818
- }
1819
- .container {
1820
- max-width: 900px;
1821
- margin: 0 auto;
1822
- background: white;
1823
- border-radius: 20px;
1824
- box-shadow: 0 20px 60px rgba(0,0,0,0.3);
1825
- overflow: hidden;
1826
- }
1827
- .header {
1828
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1829
- color: white;
1830
- padding: 30px;
1831
- text-align: center;
1832
- }
1833
- .header h1 { font-size: 2.5em; margin-bottom: 10px; }
1834
- .content { padding: 40px; }
1835
- .form-group { margin-bottom: 25px; }
1836
- label {
1837
- display: block;
1838
- font-weight: 600;
1839
- margin-bottom: 10px;
1840
- color: #333;
1841
- font-size: 16px;
1842
- }
1843
- select, input {
1844
- width: 100%;
1845
- padding: 15px;
1846
- border: 2px solid #e0e0e0;
1847
- border-radius: 10px;
1848
- font-size: 16px;
1849
- font-family: inherit;
1850
- transition: border-color 0.3s;
1851
- }
1852
- select:focus, input:focus {
1853
- outline: none;
1854
- border-color: #667eea;
1855
- }
1856
- button {
1857
- width: 100%;
1858
- padding: 18px;
1859
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1860
- color: white;
1861
- border: none;
1862
- border-radius: 10px;
1863
- font-size: 18px;
1864
- font-weight: 600;
1865
- cursor: pointer;
1866
- transition: all 0.3s;
1867
- }
1868
- button:hover {
1869
- transform: translateY(-2px);
1870
- box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
1871
- }
1872
- button:disabled {
1873
- background: #ccc;
1874
- cursor: not-allowed;
1875
- transform: none;
1876
- }
1877
- .result {
1878
- margin-top: 30px;
1879
- padding: 25px;
1880
- background: #f8f9fa;
1881
- border-radius: 10px;
1882
- border-left: 4px solid #667eea;
1883
- display: none;
1884
- }
1885
- .result.show { display: block; }
1886
- .result h3 {
1887
- color: #667eea;
1888
- margin-bottom: 20px;
1889
- font-size: 1.4em;
1890
- }
1891
- .chapter-info {
1892
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1893
- color: white;
1894
- padding: 15px 20px;
1895
- border-radius: 8px;
1896
- margin-bottom: 20px;
1897
- display: flex;
1898
- align-items: center;
1899
- gap: 10px;
1900
- font-size: 16px;
1901
- }
1902
- .chapter-icon {
1903
- font-size: 24px;
1904
- }
1905
- .chapter-text {
1906
- flex: 1;
1907
- }
1908
- .chapter-name {
1909
- font-weight: 700;
1910
- font-size: 18px;
1911
- }
1912
- .mcq-content {
1913
- background: white;
1914
- padding: 25px;
1915
- border-radius: 8px;
1916
- white-space: pre-wrap;
1917
- line-height: 1.9;
1918
- font-size: 15px;
1919
- }
1920
- .loading {
1921
- text-align: center;
1922
- padding: 30px;
1923
- display: none;
1924
- }
1925
- .loading.show { display: block; }
1926
- .spinner {
1927
- border: 4px solid #f3f3f3;
1928
- border-top: 4px solid #667eea;
1929
- border-radius: 50%;
1930
- width: 50px;
1931
- height: 50px;
1932
- animation: spin 1s linear infinite;
1933
- margin: 0 auto 15px;
1934
- }
1935
- @keyframes spin {
1936
- 0% { transform: rotate(0deg); }
1937
- 100% { transform: rotate(360deg); }
1938
- }
1939
- .subject-tag {
1940
- display: inline-block;
1941
- padding: 5px 15px;
1942
- border-radius: 20px;
1943
- font-size: 13px;
1944
- font-weight: 600;
1945
- margin-right: 10px;
1946
- }
1947
- .bio { background: #d4edda; color: #155724; }
1948
- .chem { background: #d1ecf1; color: #0c5460; }
1949
- .phy { background: #f8d7da; color: #721c24; }
1950
- .api-badge {
1951
- background: #17a2b8;
1952
- color: white;
1953
- padding: 5px 12px;
1954
- border-radius: 15px;
1955
- font-size: 12px;
1956
- margin-left: 10px;
1957
- }
1958
- </style>
1959
- </head>
1960
- <body>
1961
- <div class="container">
1962
- <div class="header">
1963
- <h1>🎓 Class 12 PCB MCQ Generator</h1>
1964
- <p style="font-size: 1.1em; margin-bottom: 15px;">
1965
- Generate practice MCQs from your textbooks
1966
- <span class="api-badge">⚡ Llama 3.3 70B</span>
1967
- </p>
1968
- <div>
1969
- <span class="subject-tag bio">Biology</span>
1970
- <span class="subject-tag chem">Chemistry</span>
1971
- <span class="subject-tag phy">Physics</span>
1972
- </div>
1973
- </div>
1974
-
1975
- <div class="content">
1976
- <div class="form-group">
1977
- <label for="subject">📚 Select Subject</label>
1978
- <select id="subject">
1979
- <option value="biology">Biology</option>
1980
- <option value="chemistry">Chemistry</option>
1981
- <option value="physics">Physics</option>
1982
- </select>
1983
- </div>
1984
-
1985
- <div class="form-group">
1986
- <label for="topic">✏️ Enter Topic</label>
1987
- <input type="text" id="topic" placeholder="e.g., Mitochondria, Chemical Bonding, Newton's Laws">
1988
- </div>
1989
-
1990
- <div class="form-group">
1991
- <label for="numQuestions">🔢 Number of MCQs</label>
1992
- <select id="numQuestions">
1993
- <option value="1">1 MCQ</option>
1994
- <option value="2">2 MCQs</option>
1995
- <option value="3">3 MCQs</option>
1996
- <option value="4">4 MCQs</option>
1997
- <option value="5" selected>5 MCQs</option>
1998
- <option value="6">6 MCQs</option>
1999
- <option value="7">7 MCQs</option>
2000
- <option value="8">8 MCQs</option>
2001
- <option value="9">9 MCQs</option>
2002
- <option value="10">10 MCQs</option>
2003
- <option value="11">11 MCQs</option>
2004
- <option value="12">12 MCQs</option>
2005
- <option value="13">13 MCQs</option>
2006
- <option value="14">14 MCQs</option>
2007
- <option value="15">15 MCQs</option>
2008
- <option value="16">16 MCQs</option>
2009
- <option value="17">17 MCQs</option>
2010
- <option value="18">18 MCQs</option>
2011
- <option value="19">19 MCQs</option>
2012
- <option value="20">20 MCQs</option>
2013
- </select>
2014
- </div>
2015
-
2016
- <button onclick="generateMCQs()">🚀 Generate MCQs</button>
2017
-
2018
- <div class="loading" id="loading">
2019
- <div class="spinner"></div>
2020
- <p style="color: #666; font-size: 16px;">Generating MCQs with AI...</p>
2021
- <p style="color: #999; font-size: 13px; margin-top: 10px;">⚡ Detecting chapter from textbook...</p>
2022
- </div>
2023
-
2024
- <div class="result" id="result">
2025
- <h3>📝 Generated MCQs:</h3>
2026
-
2027
- <div class="chapter-info" id="chapterInfo" style="display: none;">
2028
- <span class="chapter-icon">📖</span>
2029
- <div class="chapter-text">
2030
- <div style="font-size: 13px; opacity: 0.9;">Chapter:</div>
2031
- <div class="chapter-name" id="chapterName"></div>
2032
- </div>
2033
- </div>
2034
-
2035
- <div style="background: #d4edda; padding: 12px; border-radius: 6px; margin-bottom: 15px; color: #155724; font-size: 14px;">
2036
- ✓ <strong>High Quality:</strong> Generated by Llama 3.3 70B via Groq API
2037
- </div>
2038
- <div class="mcq-content" id="mcqContent"></div>
2039
- </div>
2040
- </div>
2041
- </div>
2042
- <script>
2043
- async function generateMCQs() {
2044
- const subject = document.getElementById('subject').value;
2045
- const topic = document.getElementById('topic').value.trim();
2046
- const numQuestions = parseInt(document.getElementById('numQuestions').value);
2047
-
2048
- if (!topic) {
2049
- alert('⚠️ Please enter a topic!');
2050
- return;
2051
- }
2052
-
2053
- const loading = document.getElementById('loading');
2054
- const result = document.getElementById('result');
2055
- const btn = document.querySelector('button');
2056
- const chapterInfo = document.getElementById('chapterInfo');
2057
-
2058
- loading.classList.add('show');
2059
- result.classList.remove('show');
2060
- chapterInfo.style.display = 'none';
2061
- btn.disabled = true;
2062
- btn.textContent = '⏳ Generating...';
2063
-
2064
- try {
2065
- const response = await fetch('/generate', {
2066
- method: 'POST',
2067
- headers: {'Content-Type': 'application/json'},
2068
- body: JSON.stringify({subject, topic, num_questions: numQuestions})
2069
- });
2070
-
2071
- const data = await response.json();
2072
-
2073
- if (data.error) {
2074
- alert('❌ Error: ' + data.error);
2075
- return;
2076
- }
2077
-
2078
- // Display chapter info
2079
- if (data.chapter && data.chapter !== 'Unknown Chapter') {
2080
- document.getElementById('chapterName').textContent = data.chapter;
2081
- chapterInfo.style.display = 'flex';
2082
- }
2083
-
2084
- document.getElementById('mcqContent').textContent = data.mcqs;
2085
- result.classList.add('show');
2086
- } catch (error) {
2087
- alert('❌ Error: ' + error.message);
2088
- } finally {
2089
- loading.classList.remove('show');
2090
- btn.disabled = false;
2091
- btn.textContent = '🚀 Generate MCQs';
2092
- }
2093
- }
2094
-
2095
- document.getElementById('topic').addEventListener('keypress', function(e) {
2096
- if (e.key === 'Enter') {
2097
- generateMCQs();
2098
- }
2099
- });
2100
- </script>
2101
- </body>
2102
- </html>
2103
- """
2104
-
2105
- # ------------------------------
2106
- # Routes
2107
- # ------------------------------
2108
- @app.route("/")
2109
- def home():
2110
- return render_template_string(HTML_TEMPLATE)
2111
-
2112
- @app.route("/generate", methods=["POST"])
2113
- def generate():
2114
- try:
2115
- data = request.json
2116
- subject = data.get("subject", "").lower()
2117
- topic = data.get("topic", "")
2118
- num_questions = data.get("num_questions", 5)
2119
-
2120
- # Validate num_questions
2121
- try:
2122
- num_questions = int(num_questions)
2123
- if num_questions < 1 or num_questions > 20:
2124
- num_questions = 5
2125
- except:
2126
- num_questions = 5
2127
-
2128
- if not topic:
2129
- return jsonify({"error": "Topic is required"}), 400
2130
-
2131
- if subject not in SUBJECTS:
2132
- return jsonify({"error": "Invalid subject"}), 400
2133
-
2134
- print(f"\n🔍 Validating topic for {subject}...")
2135
-
2136
- # STEP 1: Validate if topic belongs to subject (BEFORE RAG search)
2137
- if not validate_topic_subject(topic, subject):
2138
- subject_names = {
2139
- "biology": "Biology",
2140
- "chemistry": "Chemistry",
2141
- "physics": "Physics"
2142
- }
2143
- 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"
2144
- return jsonify({"error": error_msg}), 400
2145
-
2146
- print(f"✓ Topic validated for {subject}")
2147
- print(f"🔍 Searching {subject} for: {topic}")
2148
-
2149
- # STEP 2: RAG search
2150
- context = rag_search(topic, subject, k=5)
2151
-
2152
- if not context or len(context.strip()) < 50:
2153
- return jsonify({"error": f"No content found for: {topic}"}), 404
2154
-
2155
- print(f"✓ Context found ({len(context)} chars)")
2156
-
2157
- # STEP 3: Generate MCQs
2158
- mcqs, chapter = generate_mcqs(context, topic, subject, num_questions)
2159
-
2160
- # Check if there was a subject mismatch
2161
- if chapter is None:
2162
- return jsonify({"error": mcqs}), 400
2163
-
2164
- return jsonify({
2165
- "mcqs": mcqs,
2166
- "subject": subject,
2167
- "chapter": chapter
2168
- })
2169
-
2170
- except Exception as e:
2171
- print(f"❌ Error: {e}")
2172
- import traceback
2173
- traceback.print_exc()
2174
- return jsonify({"error": str(e)}), 500
2175
-
2176
- @app.route("/health")
2177
- def health():
2178
- return jsonify({
2179
- "status": "healthy",
2180
- "groq_available": groq_client is not None,
2181
- "cache_size": len(MCQ_CACHE)
2182
- })
2183
-
2184
- # ------------------------------
2185
- # Run
2186
- # ------------------------------
2187
- if __name__ == "__main__":
2188
- port = int(os.environ.get("PORT", 7860))
2189
- print(f"\n🚀 Starting server on port {port}...\n")
2190
- app.run(host="0.0.0.0", port=port, debug=False)
2191
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import pickle
2
  import faiss
3
  from flask import Flask, request, jsonify, render_template_string
 
497
  if line.startswith('Correct Answer:'):
498
  line = line.replace('Correct Answer:', 'Answer:')
499
 
500
+ cleaned_lines.append(line)
501
+
502
+ return '\n'.join(cleaned_lines)
 
503
 
504
  # ------------------------------
505
  # HTML UI
 
888
  if __name__ == "__main__":
889
  port = int(os.environ.get("PORT", 7860))
890
  print(f"\n🚀 Starting server on port {port}...\n")
891
+ app.run(host="0.0.0.0", port=port, debug=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
892